#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include "as.h"
#include "safe-ctype.h"
#include "sb.h"
#include "macro.h"
#include "subsegs.h"
#include "struc-symbol.h"
#include "opcode/tic54x.h"
#include "obj-coff.h"
#include <math.h>
static struct stag
{
symbolS *sym;
const char *name;
bfd_vma size;
int current_bitfield_offset;
int is_union;
struct stag_field
{
const char *name;
bfd_vma offset;
int bitfield_offset;
struct stag *stag;
struct stag_field *next;
} *field;
struct stag *inner;
struct stag *outer;
} *current_stag = NULL;
#define MAX_LINE 256
typedef struct _tic54x_insn
{
const template *tm;
char mnemonic[MAX_LINE];
char parmnemonic[MAX_LINE];
int opcount;
struct opstruct
{
char buf[MAX_LINE];
enum optype type;
expressionS exp;
} operands[MAX_OPERANDS];
int paropcount;
struct opstruct paroperands[MAX_OPERANDS];
int is_lkaddr;
int lkoperand;
int words;
int using_default_dst;
struct
{
unsigned short word;
int unresolved;
int r_nchars;
bfd_reloc_code_real_type r_type;
expressionS addr_expr;
} opcode[3];
} tic54x_insn;
enum cpu_version
{
VNONE = 0, V541 = 1, V542 = 2, V543 = 3, V545 = 5, V548 = 8, V549 = 9,
V545LP = 15, V546LP = 16
};
enum address_mode
{
c_mode,
far_mode
};
static segT stag_saved_seg;
static subsegT stag_saved_subseg;
const char comment_chars[] = ";";
const char line_comment_chars[] = ";*#";
const char line_separator_chars[] = "";
int emitting_long = 0;
const char FLT_CHARS[] = "fF";
const char EXP_CHARS[] = "eE";
const char *md_shortopts = "";
#define OPTION_ADDRESS_MODE (OPTION_MD_BASE)
#define OPTION_CPU_VERSION (OPTION_ADDRESS_MODE + 1)
#define OPTION_COFF_VERSION (OPTION_CPU_VERSION + 1)
#define OPTION_STDERR_TO_FILE (OPTION_COFF_VERSION + 1)
struct option md_longopts[] =
{
{ "mfar-mode", no_argument, NULL, OPTION_ADDRESS_MODE },
{ "mf", no_argument, NULL, OPTION_ADDRESS_MODE },
{ "mcpu", required_argument, NULL, OPTION_CPU_VERSION },
{ "merrors-to-file", required_argument, NULL, OPTION_STDERR_TO_FILE },
{ "me", required_argument, NULL, OPTION_STDERR_TO_FILE },
{ NULL, no_argument, NULL, 0},
};
size_t md_longopts_size = sizeof (md_longopts);
static int assembly_begun = 0;
static enum address_mode amode = c_mode;
static enum cpu_version cpu = VNONE;
static int listing_sslist = 0;
static int substitution_line = 0;
static symbolS *last_label_seen = NULL;
static int local_label_id;
static struct hash_control *subsym_recurse_hash;
static struct hash_control *math_hash;
static struct hash_control *subsym_hash[100];
static int macro_level = 0;
static struct hash_control *local_label_hash[100];
static struct hash_control *stag_hash;
static struct hash_control *op_hash;
static struct hash_control *parop_hash;
static struct hash_control *reg_hash;
static struct hash_control *mmreg_hash;
static struct hash_control *cc_hash;
static struct hash_control *cc2_hash;
static struct hash_control *cc3_hash;
static struct hash_control *sbit_hash;
static struct hash_control *misc_symbol_hash;
#define ILLEGAL_WITHIN_STRUCT() \
do \
if (current_stag != NULL) \
{ \
as_bad (_("pseudo-op illegal within .struct/.union")); \
return; \
} \
while (0)
static void tic54x_emit_char PARAMS ((char));
static fragS * frag_prev PARAMS ((fragS *, segT));
static fragS * bit_offset_frag PARAMS ((fragS *, segT));
static int frag_bit_offset PARAMS ((fragS *, segT));
static char * parse_expression PARAMS ((char *, expressionS *));
static void tic54x_asg PARAMS ((int));
static void tic54x_eval PARAMS ((int));
static void tic54x_bss PARAMS ((int));
static void stag_add_field_symbols PARAMS ((struct stag *, const char *, bfd_vma, symbolS *, const char *));
static void stag_add_field PARAMS ((struct stag *, const char *, bfd_vma, struct stag *));
static void tic54x_struct PARAMS ((int));
static void tic54x_endstruct PARAMS ((int));
static void tic54x_tag PARAMS ((int));
static void tic54x_struct_field PARAMS ((int));
static void tic54x_cons PARAMS ((int));
static void tic54x_remove_local_label PARAMS ((const char *, PTR));
static void tic54x_clear_local_labels PARAMS ((int));
static void tic54x_sect PARAMS ((int));
static void tic54x_space PARAMS ((int));
static void tic54x_usect PARAMS ((int));
static enum cpu_version lookup_version PARAMS ((const char *));
static void set_cpu PARAMS ((enum cpu_version));
static void tic54x_version PARAMS ((int));
static void tic54x_float_cons PARAMS ((int));
static void tic54x_stringer PARAMS ((int));
static void tic54x_p2align PARAMS ((int));
static void tic54x_align_words PARAMS ((int));
static void tic54x_field PARAMS ((int));
static int tic54x_initialized_section PARAMS ((segT));
static void tic54x_clink PARAMS ((int));
static void tic54x_set_default_include PARAMS ((int));
static void tic54x_include PARAMS ((int));
static void tic54x_message PARAMS ((int));
static void tic54x_label PARAMS ((int));
static void tic54x_mmregs PARAMS ((int));
static void tic54x_loop PARAMS ((int));
static void tic54x_endloop PARAMS ((int));
static void tic54x_break PARAMS ((int));
static void set_address_mode PARAMS ((int));
static void tic54x_address_mode PARAMS ((int));
static void tic54x_sblock PARAMS ((int));
static void tic54x_set PARAMS ((int));
static void tic54x_fclist PARAMS ((int));
static void tic54x_sslist PARAMS ((int));
static void tic54x_var PARAMS ((int));
static void tic54x_mlib PARAMS ((int));
static int subsym_symlen PARAMS ((char *, char *));
static int subsym_symcmp PARAMS ((char *, char *));
static int subsym_firstch PARAMS ((char *, char *));
static int subsym_lastch PARAMS ((char *, char *));
static int subsym_isdefed PARAMS ((char *, char *));
static int subsym_ismember PARAMS ((char *, char *));
static int subsym_iscons PARAMS ((char *, char *));
static int subsym_isname PARAMS ((char *, char *));
static int subsym_isreg PARAMS ((char *, char *));
static int subsym_structsz PARAMS ((char *, char *));
static int subsym_structacc PARAMS ((char *, char *));
static float math_ceil PARAMS ((float, float));
static float math_cvi PARAMS ((float, float));
static float math_floor PARAMS ((float, float));
static float math_fmod PARAMS ((float, float));
static float math_int PARAMS ((float, float));
static float math_round PARAMS ((float, float));
static float math_sgn PARAMS ((float, float));
static float math_trunc PARAMS ((float, float));
static float math_acos PARAMS ((float, float));
static float math_asin PARAMS ((float, float));
static float math_atan PARAMS ((float, float));
static float math_atan2 PARAMS ((float, float));
static float math_cosh PARAMS ((float, float));
static float math_cos PARAMS ((float, float));
static float math_cvf PARAMS ((float, float));
static float math_exp PARAMS ((float, float));
static float math_fabs PARAMS ((float, float));
static float math_ldexp PARAMS ((float, float));
static float math_log10 PARAMS ((float, float));
static float math_log PARAMS ((float, float));
static float math_max PARAMS ((float, float));
static float math_min PARAMS ((float, float));
static float math_pow PARAMS ((float, float));
static float math_sin PARAMS ((float, float));
static float math_sinh PARAMS ((float, float));
static float math_sqrt PARAMS ((float, float));
static float math_tan PARAMS ((float, float));
static float math_tanh PARAMS ((float, float));
static int is_accumulator PARAMS ((struct opstruct *));
static int get_operands PARAMS ((struct opstruct operands[], char *));
static int is_immediate PARAMS ((struct opstruct *));
static int is_absolute PARAMS ((struct opstruct *));
static int is_indirect PARAMS ((struct opstruct *));
static int is_dual PARAMS ((struct opstruct *));
static int is_mmreg PARAMS ((struct opstruct *));
static int is_type PARAMS ((struct opstruct *, enum optype));
static int operands_match PARAMS ((tic54x_insn *, struct opstruct *, int, const enum optype *, int, int));
static int encode_dmad PARAMS ((tic54x_insn *, struct opstruct *, int));
static int encode_address PARAMS ((tic54x_insn *, struct opstruct *));
static int encode_indirect PARAMS ((tic54x_insn *, struct opstruct *));
static int encode_integer PARAMS ((tic54x_insn *, struct opstruct *, int, int, int, unsigned short));
static int encode_condition PARAMS ((tic54x_insn *, struct opstruct *));
static int encode_cc3 PARAMS ((tic54x_insn *, struct opstruct *));
static int encode_arx PARAMS ((tic54x_insn *, struct opstruct *));
static int encode_cc2 PARAMS ((tic54x_insn *, struct opstruct *));
static int encode_operand PARAMS ((tic54x_insn *, enum optype, struct opstruct *));
static void emit_insn PARAMS ((tic54x_insn *));
static int build_insn PARAMS ((tic54x_insn *));
static int optimize_insn PARAMS ((tic54x_insn *));
static int tic54x_parse_insn PARAMS ((tic54x_insn *, char *));
static int next_line_shows_parallel PARAMS ((char *));
static int tic54x_parse_parallel_insn_firstline PARAMS ((tic54x_insn *, char *));
static int tic54x_parse_parallel_insn_lastline PARAMS ((tic54x_insn *, char *));
static char * subsym_get_arg PARAMS ((char *, char *, char **, int));
static void subsym_create_or_replace PARAMS ((char *, char *));
static char * subsym_lookup PARAMS ((char *, int));
static char * subsym_substitute PARAMS ((char *, int));
void
md_show_usage (stream)
FILE *stream;
{
fprintf (stream, _("C54x-specific command line options:\n"));
fprintf (stream, _("-mfar-mode | -mf Use extended addressing\n"));
fprintf (stream, _("-mcpu=<CPU version> Specify the CPU version\n"));
fprintf (stream, _("-merrors-to-file <filename>\n"));
fprintf (stream, _("-me <filename> Redirect errors to a file\n"));
}
static void
tic54x_emit_char (c)
char c;
{
expressionS exp;
exp.X_op = O_constant;
exp.X_add_number = c;
emit_expr (&exp, 2);
}
static fragS *
frag_prev (frag, seg)
fragS *frag;
segT seg;
{
segment_info_type *seginfo = seg_info (seg);
fragS *fragp;
for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
if (fragp->fr_next == frag)
return fragp;
return NULL;
}
static fragS *
bit_offset_frag (frag, seg)
fragS *frag;
segT seg;
{
while (frag != NULL)
{
if (frag->fr_fix == 0
&& frag->fr_opcode == NULL
&& frag->tc_frag_data == 0)
frag = frag_prev (frag, seg);
else
return frag;
}
return NULL;
}
static int
frag_bit_offset (frag, seg)
fragS *frag;
segT seg;
{
frag = bit_offset_frag (frag, seg);
if (frag)
return frag->fr_opcode != NULL ? -1 : frag->tc_frag_data;
return 0;
}
static char *
parse_expression (str, exp)
char *str;
expressionS * exp;
{
char *s;
char *tmp;
tmp = input_line_pointer;
input_line_pointer = str;
expression (exp);
s = input_line_pointer;
input_line_pointer = tmp;
return s;
}
static void
tic54x_asg (x)
int x ATTRIBUTE_UNUSED;
{
int c;
char *name;
char *str;
char *tmp;
int quoted = *input_line_pointer == '"';
ILLEGAL_WITHIN_STRUCT ();
if (quoted)
{
int len;
str = demand_copy_C_string (&len);
c = *input_line_pointer;
}
else
{
str = input_line_pointer;
while ((c = *input_line_pointer) != ',')
{
if (is_end_of_line[(int) *input_line_pointer])
break;
++input_line_pointer;
}
*input_line_pointer = 0;
}
if (c != ',')
{
as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'"));
ignore_rest_of_line ();
return;
}
name = ++input_line_pointer;
c = get_symbol_end ();
if (!ISALPHA (*name))
{
as_bad ("symbols assigned with .asg must begin with a letter");
ignore_rest_of_line ();
return;
}
tmp = xmalloc (strlen (str) + 1);
strcpy (tmp, str);
str = tmp;
tmp = xmalloc (strlen (name) + 1);
strcpy (tmp, name);
name = tmp;
subsym_create_or_replace (name, str);
*input_line_pointer = c;
demand_empty_rest_of_line ();
}
static void
tic54x_eval (x)
int x ATTRIBUTE_UNUSED;
{
char c;
int value;
char *name;
symbolS *symbolP;
char valuestr[32], *tmp;
int quoted;
ILLEGAL_WITHIN_STRUCT ();
SKIP_WHITESPACE ();
quoted = *input_line_pointer == '"';
if (quoted)
++input_line_pointer;
value = get_absolute_expression ();
if (quoted)
{
if (*input_line_pointer != '"')
{
as_bad (_("Unterminated string after absolute expression"));
ignore_rest_of_line ();
return;
}
++input_line_pointer;
}
if (*input_line_pointer++ != ',')
{
as_bad (_("Comma and symbol expected for '.eval EXPR, SYMBOL'"));
ignore_rest_of_line ();
return;
}
name = input_line_pointer;
c = get_symbol_end ();
tmp = xmalloc (strlen (name) + 1);
name = strcpy (tmp, name);
*input_line_pointer = c;
if (!ISALPHA (*name))
{
as_bad (_("symbols assigned with .eval must begin with a letter"));
ignore_rest_of_line ();
return;
}
symbolP = symbol_new (name, absolute_section,
(valueT) value, &zero_address_frag);
SF_SET_LOCAL (symbolP);
symbol_table_insert (symbolP);
sprintf (valuestr, "%d", value);
tmp = xmalloc (strlen (valuestr) + 1);
strcpy (tmp, valuestr);
subsym_create_or_replace (name, tmp);
demand_empty_rest_of_line ();
}
static void
tic54x_bss (x)
int x ATTRIBUTE_UNUSED;
{
char c;
char *name;
char *p;
int words;
segT current_seg;
subsegT current_subseg;
symbolS *symbolP;
int block = 0;
int align = 0;
ILLEGAL_WITHIN_STRUCT ();
current_seg = now_seg;
current_subseg = now_subseg;
name = input_line_pointer;
c = get_symbol_end ();
if (c != ',')
{
as_bad (".bss size argument missing\n");
ignore_rest_of_line ();
return;
}
++input_line_pointer;
words = get_absolute_expression ();
if (words < 0)
{
as_bad (".bss size %d < 0!", words);
ignore_rest_of_line ();
return;
}
if (*input_line_pointer == ',')
{
++input_line_pointer;
if (*input_line_pointer != ',')
block = get_absolute_expression ();
else
block = 0;
if (*input_line_pointer == ',')
{
++input_line_pointer;
align = get_absolute_expression ();
}
else
align = 0;
}
else
block = align = 0;
subseg_set (bss_section, 0);
symbolP = symbol_find_or_make (name);
if (S_GET_SEGMENT (symbolP) == bss_section)
symbolP->sy_frag->fr_symbol = (symbolS *) NULL;
symbol_set_frag (symbolP, frag_now);
p = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
(offsetT) (words * OCTETS_PER_BYTE), (char *) 0);
*p = 0;
S_SET_SEGMENT (symbolP, bss_section);
if (S_GET_STORAGE_CLASS (symbolP) != C_EXT)
S_SET_STORAGE_CLASS (symbolP, C_STAT);
if (align)
{
s_align_bytes (4);
--input_line_pointer;
}
if (block)
bss_section->flags |= SEC_TIC54X_BLOCK;
subseg_set (current_seg, current_subseg);
demand_empty_rest_of_line ();
}
static void
stag_add_field_symbols (stag, path, base_offset, rootsym, root_stag_name)
struct stag *stag;
const char *path;
bfd_vma base_offset;
symbolS *rootsym;
const char *root_stag_name;
{
char prefix[strlen (path) + 2];
struct stag_field *field = stag->field;
strcpy (prefix, path);
if (*path)
strcat (prefix, ".");
while (field != NULL)
{
int len = strlen (prefix) + strlen (field->name) + 2;
char *name = xmalloc (len);
strcpy (name, prefix);
strcat (name, field->name);
if (rootsym == NULL)
{
symbolS *sym;
sym = symbol_new (name, absolute_section,
(field->stag ? field->offset :
(valueT) (base_offset + field->offset)),
&zero_address_frag);
SF_SET_LOCAL (sym);
symbol_table_insert (sym);
}
else
{
char *replacement = xmalloc (strlen (name)
+ strlen (stag->name) + 2);
strcpy (replacement, S_GET_NAME (rootsym));
strcat (replacement, "+");
strcat (replacement, root_stag_name);
strcat (replacement, name + strlen (S_GET_NAME (rootsym)));
hash_insert (subsym_hash[0], name, replacement);
}
if (field->stag != NULL)
stag_add_field_symbols (field->stag, name,
field->offset,
rootsym, root_stag_name);
field = field->next;
}
}
static void
stag_add_field (parent, name, offset, stag)
struct stag *parent;
const char *name;
bfd_vma offset;
struct stag *stag;
{
struct stag_field *sfield = xmalloc (sizeof (struct stag_field));
memset (sfield, 0, sizeof (*sfield));
sfield->name = strcpy (xmalloc (strlen (name) + 1), name);
sfield->offset = offset;
sfield->bitfield_offset = parent->current_bitfield_offset;
sfield->stag = stag;
if (parent->field == NULL)
parent->field = sfield;
else
{
struct stag_field *sf = parent->field;
while (sf->next != NULL)
sf = sf->next;
sf->next = sfield;
}
if (!strncmp (".fake", parent->name, 5))
{
symbolS *sym = symbol_new (name, absolute_section,
(valueT) offset, &zero_address_frag);
SF_SET_LOCAL (sym);
symbol_table_insert (sym);
}
}
static void
tic54x_struct (arg)
int arg;
{
int start_offset = 0;
int is_union = arg;
if (!current_stag)
{
stag_saved_seg = now_seg;
stag_saved_subseg = now_subseg;
subseg_set (absolute_section, 0);
}
else if (current_stag->current_bitfield_offset != 0)
{
++abs_section_offset;
current_stag->current_bitfield_offset = 0;
}
if (!is_union)
{
SKIP_WHITESPACE ();
if (!is_end_of_line[(int) *input_line_pointer])
start_offset = get_absolute_expression ();
else
start_offset = 0;
}
if (current_stag)
{
current_stag->inner = (struct stag *) xmalloc (sizeof (struct stag));
memset (current_stag->inner, 0, sizeof (struct stag));
current_stag->inner->outer = current_stag;
current_stag = current_stag->inner;
if (start_offset)
as_warn (_("Offset on nested structures is ignored"));
start_offset = abs_section_offset;
}
else
{
current_stag = (struct stag *) xmalloc (sizeof (struct stag));
memset (current_stag, 0, sizeof (struct stag));
abs_section_offset = start_offset;
}
current_stag->is_union = is_union;
if (line_label == NULL)
{
static int struct_count = 0;
char fake[] = ".fake_stagNNNNNNN";
sprintf (fake, ".fake_stag%d", struct_count++);
current_stag->sym = symbol_new (fake, absolute_section,
(valueT) abs_section_offset,
&zero_address_frag);
}
else
{
char label[strlen (S_GET_NAME (line_label)) + 1];
strcpy (label, S_GET_NAME (line_label));
current_stag->sym = symbol_new (label, absolute_section,
(valueT) abs_section_offset,
&zero_address_frag);
}
current_stag->name = S_GET_NAME (current_stag->sym);
SF_SET_LOCAL (current_stag->sym);
if (current_stag->outer == NULL)
symbol_table_insert (current_stag->sym);
line_label = NULL;
}
static void
tic54x_endstruct (is_union)
int is_union;
{
int size;
const char *path =
!strncmp (current_stag->name, ".fake", 5) ? "" : current_stag->name;
if (!current_stag || current_stag->is_union != is_union)
{
as_bad (_(".end%s without preceding .%s"),
is_union ? "union" : "struct",
is_union ? "union" : "struct");
ignore_rest_of_line ();
return;
}
if (current_stag->current_bitfield_offset)
{
++abs_section_offset;
current_stag->current_bitfield_offset = 0;
}
if (current_stag->is_union)
size = current_stag->size;
else
size = abs_section_offset - S_GET_VALUE (current_stag->sym);
if (line_label != NULL)
{
S_SET_VALUE (line_label, size);
symbol_table_insert (line_label);
line_label = NULL;
}
if (!current_stag->is_union)
current_stag->size = size;
if (current_stag->outer == NULL)
{
hash_insert (stag_hash, current_stag->name, current_stag);
stag_add_field_symbols (current_stag, path,
S_GET_VALUE (current_stag->sym),
NULL, NULL);
}
current_stag = current_stag->outer;
if (current_stag != NULL)
{
stag_add_field (current_stag, current_stag->inner->name,
S_GET_VALUE (current_stag->inner->sym),
current_stag->inner);
}
else
subseg_set (stag_saved_seg, stag_saved_subseg);
}
static void
tic54x_tag (ignore)
int ignore ATTRIBUTE_UNUSED;
{
char *name = input_line_pointer;
int c = get_symbol_end ();
struct stag *stag = (struct stag *) hash_find (stag_hash, name);
if (!stag)
{
if (*name)
as_bad (_("Unrecognized struct/union tag '%s'"), name);
else
as_bad (_(".tag requires a structure tag"));
ignore_rest_of_line ();
return;
}
if (line_label == NULL)
{
as_bad (_("Label required for .tag"));
ignore_rest_of_line ();
return;
}
else
{
char label[strlen (S_GET_NAME (line_label)) + 1];
strcpy (label, S_GET_NAME (line_label));
if (current_stag != NULL)
stag_add_field (current_stag, label,
abs_section_offset - S_GET_VALUE (current_stag->sym),
stag);
else
{
symbolS *sym = symbol_find (label);
if (!sym)
{
as_bad (_(".tag target '%s' undefined"), label);
ignore_rest_of_line ();
return;
}
stag_add_field_symbols (stag, S_GET_NAME (sym),
S_GET_VALUE (stag->sym), sym, stag->name);
}
}
if (current_stag != NULL && !current_stag->is_union)
abs_section_offset += stag->size;
*input_line_pointer = c;
demand_empty_rest_of_line ();
line_label = NULL;
}
static void
tic54x_struct_field (type)
int type;
{
int size;
int count = 1;
int new_bitfield_offset = 0;
int field_align = current_stag->current_bitfield_offset != 0;
int longword_align = 0;
SKIP_WHITESPACE ();
if (!is_end_of_line[(int) *input_line_pointer])
count = get_absolute_expression ();
switch (type)
{
case 'b':
case 'B':
case 'c':
case 'C':
case 'h':
case 'H':
case 'i':
case 'I':
case 's':
case 'S':
case 'w':
case 'W':
case '*':
size = 1;
break;
case 'f':
case 'l':
case 'L':
longword_align = 1;
size = 2;
break;
case '.':
size = 0;
if (count < 1 || count > 32)
{
as_bad (_(".field count '%d' out of range (1 <= X <= 32)"), count);
ignore_rest_of_line ();
return;
}
if (current_stag->current_bitfield_offset + count > 16)
{
if (count == 32)
{
size = 2;
count = 1;
}
else if (count > 16)
{
size = 1;
count = 1;
new_bitfield_offset = count - 16;
}
else
new_bitfield_offset = count;
}
else
{
field_align = 0;
new_bitfield_offset = current_stag->current_bitfield_offset + count;
}
break;
default:
as_bad (_("Unrecognized field type '%c'"), type);
ignore_rest_of_line ();
return;
}
if (field_align)
{
current_stag->current_bitfield_offset = 0;
++abs_section_offset;
}
if (longword_align && (abs_section_offset & 0x1))
++abs_section_offset;
if (line_label == NULL)
{
static int fieldno = 0;
char fake[] = ".fake_fieldNNNNN";
sprintf (fake, ".fake_field%d", fieldno++);
stag_add_field (current_stag, fake,
abs_section_offset - S_GET_VALUE (current_stag->sym),
NULL);
}
else
{
char label[strlen (S_GET_NAME (line_label) + 1)];
strcpy (label, S_GET_NAME (line_label));
stag_add_field (current_stag, label,
abs_section_offset - S_GET_VALUE (current_stag->sym),
NULL);
}
if (current_stag->is_union)
{
if (current_stag->size < (unsigned) size * count)
current_stag->size = size * count;
}
else
{
abs_section_offset += (unsigned) size * count;
current_stag->current_bitfield_offset = new_bitfield_offset;
}
line_label = NULL;
}
static void
tic54x_cons (type)
int type;
{
unsigned int c;
int octets;
if (current_stag != NULL)
{
tic54x_struct_field (type);
return;
}
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
generate_lineno_debug ();
if (type == 'l' || type == 'L')
{
frag_align (2, 0, 2);
if (line_label != NULL)
{
symbol_set_frag (line_label, frag_now);
S_SET_VALUE (line_label, frag_now_fix ());
}
}
switch (type)
{
case 'l':
case 'L':
case 'x':
octets = 4;
break;
case 'b':
case 'B':
case 'c':
case 'C':
octets = 1;
break;
default:
octets = 2;
break;
}
do
{
if (*input_line_pointer == '"')
{
input_line_pointer++;
while (is_a_char (c = next_char_of_string ()))
tic54x_emit_char (c);
know (input_line_pointer[-1] == '\"');
}
else
{
expressionS exp;
input_line_pointer = parse_expression (input_line_pointer, &exp);
if (exp.X_op == O_constant)
{
offsetT value = exp.X_add_number;
switch (octets)
{
case 1:
if ((value > 0 && value > 0xFF)
|| (value < 0 && value < - 0x100))
as_warn ("Overflow in expression, truncated to 8 bits");
break;
case 2:
if ((value > 0 && value > 0xFFFF)
|| (value < 0 && value < - 0x10000))
as_warn ("Overflow in expression, truncated to 16 bits");
break;
}
}
if (exp.X_op != O_constant && octets < 2)
{
as_bad (_("Relocatable values require at least WORD storage"));
ignore_rest_of_line ();
return;
}
if (exp.X_op != O_constant
&& amode == c_mode
&& octets == 4)
{
amode = far_mode;
emitting_long = 1;
emit_expr (&exp, 4);
emitting_long = 0;
amode = c_mode;
}
else
{
emitting_long = octets == 4;
emit_expr (&exp, (octets == 1) ? 2 : octets);
emitting_long = 0;
}
}
}
while (*input_line_pointer++ == ',');
input_line_pointer--;
demand_empty_rest_of_line ();
}
void
tic54x_global (type)
int type;
{
char *name;
int c;
symbolS *symbolP;
if (type == 'r')
as_warn (_("Use of .def/.ref is deprecated. Use .global instead"));
ILLEGAL_WITHIN_STRUCT ();
do
{
name = input_line_pointer;
c = get_symbol_end ();
symbolP = symbol_find_or_make (name);
*input_line_pointer = c;
S_SET_STORAGE_CLASS (symbolP, C_EXT);
if (c == ',')
{
input_line_pointer++;
if (is_end_of_line[(int) *input_line_pointer])
c = *input_line_pointer;
}
}
while (c == ',');
demand_empty_rest_of_line ();
}
static void
tic54x_remove_local_label (key, value)
const char *key;
PTR value ATTRIBUTE_UNUSED;
{
PTR *elem = hash_delete (local_label_hash[macro_level], key);
free (elem);
}
static void
tic54x_clear_local_labels (ignored)
int ignored ATTRIBUTE_UNUSED;
{
hash_traverse (local_label_hash[macro_level], tic54x_remove_local_label);
}
static void
tic54x_sect (arg)
int arg;
{
ILLEGAL_WITHIN_STRUCT ();
tic54x_clear_local_labels (0);
if (arg == 't')
s_text (0);
else if (arg == 'd')
s_data (0);
else
{
char *name = NULL;
int len;
if (*input_line_pointer == '"')
{
name = demand_copy_C_string (&len);
demand_empty_rest_of_line ();
name = strcpy (xmalloc (len + 10), name);
}
else
{
int c;
name = input_line_pointer;
c = get_symbol_end ();
len = strlen(name);
name = strcpy (xmalloc (len + 10), name);
*input_line_pointer = c;
demand_empty_rest_of_line ();
}
strcat (name, ",\"w\"\n");
input_scrub_insert_line (name);
obj_coff_section (0);
if (line_label != NULL)
{
S_SET_SEGMENT (line_label, now_seg);
symbol_set_frag (line_label, frag_now);
S_SET_VALUE (line_label, frag_now_fix ());
if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
S_SET_STORAGE_CLASS (line_label, C_LABEL);
}
}
}
static void
tic54x_space (arg)
int arg;
{
expressionS exp;
char *p = 0;
int octets = 0;
long words;
int bits_per_byte = (OCTETS_PER_BYTE * 8);
int bit_offset = 0;
symbolS *label = line_label;
int bes = arg;
ILLEGAL_WITHIN_STRUCT ();
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
expression (&exp);
if (exp.X_op != O_constant || frag_bit_offset (frag_now, now_seg) == -1)
{
struct bit_info *bi = xmalloc (sizeof (struct bit_info));
char *p;
bi->seg = now_seg;
bi->type = bes;
bi->sym = label;
p = frag_var (rs_machine_dependent,
65536 * 2, 1, (relax_substateT) 0,
make_expr_symbol (&exp), (offsetT) 0,
(char *) bi);
if (p)
*p = 0;
return;
}
bit_offset = frag_now->tc_frag_data;
if (bit_offset != 0 && bit_offset < 16)
{
int spare_bits = bits_per_byte - bit_offset;
if (spare_bits >= exp.X_add_number)
{
if (label != NULL)
{
symbol_set_frag (label, frag_now);
S_SET_VALUE (label, frag_now_fix () - 1);
label = NULL;
}
frag_now->tc_frag_data += exp.X_add_number;
goto getout;
}
exp.X_add_number -= spare_bits;
if (!bes && label != NULL)
{
symbol_set_frag (label, frag_now);
S_SET_VALUE (label, frag_now_fix () - 1);
label = NULL;
}
}
words = ((exp.X_add_number + bits_per_byte - 1) / bits_per_byte);
bit_offset = exp.X_add_number % bits_per_byte;
octets = words * OCTETS_PER_BYTE;
if (octets < 0)
{
as_warn (_(".space/.bes repeat count is negative, ignored"));
goto getout;
}
else if (octets == 0)
{
as_warn (_(".space/.bes repeat count is zero, ignored"));
goto getout;
}
if (now_seg == absolute_section)
{
abs_section_offset += words;
if (bes && label != NULL)
S_SET_VALUE (label, abs_section_offset - 1);
frag_now->tc_frag_data = bit_offset;
goto getout;
}
if (!need_pass_2)
p = frag_var (rs_fill, 1, 1,
(relax_substateT) 0, (symbolS *) 0,
(offsetT) octets, (char *) 0);
frag_now->tc_frag_data = bit_offset;
if (bes && label != NULL)
{
symbol_set_frag (label, frag_now);
S_SET_VALUE (label, frag_now_fix () - 1);
}
if (p)
*p = 0;
getout:
demand_empty_rest_of_line ();
}
static void
tic54x_usect (x)
int x ATTRIBUTE_UNUSED;
{
char c;
char *name;
char *section_name;
char *p;
segT seg;
int size, blocking_flag, alignment_flag;
segT current_seg;
subsegT current_subseg;
flagword flags;
ILLEGAL_WITHIN_STRUCT ();
current_seg = now_seg;
current_subseg = now_subseg;
if (*input_line_pointer == '"')
input_line_pointer++;
section_name = input_line_pointer;
c = get_symbol_end ();
input_line_pointer++;
name = xmalloc (input_line_pointer - section_name + 1);
strcpy (name, section_name);
if (*input_line_pointer == ',')
++input_line_pointer;
else if (c != ',')
{
as_bad (_("Missing size argument"));
ignore_rest_of_line ();
return;
}
size = get_absolute_expression ();
if (*input_line_pointer == ',')
{
++input_line_pointer;
if (*input_line_pointer != ',')
blocking_flag = get_absolute_expression ();
else
blocking_flag = 0;
if (*input_line_pointer == ',')
{
++input_line_pointer;
alignment_flag = get_absolute_expression ();
}
else
alignment_flag = 0;
}
else
blocking_flag = alignment_flag = 0;
seg = subseg_new (name, 0);
flags = bfd_get_section_flags (stdoutput, seg) | SEC_ALLOC;
if (alignment_flag)
{
s_align_bytes (4);
--input_line_pointer;
}
if (line_label != NULL)
{
S_SET_SEGMENT (line_label, seg);
symbol_set_frag (line_label, frag_now);
S_SET_VALUE (line_label, frag_now_fix ());
if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
S_SET_STORAGE_CLASS (line_label, C_LABEL);
}
seg_info (seg)->bss = 1;
p = frag_var (rs_fill, 1, 1,
(relax_substateT) 0, (symbolS *) line_label,
size * OCTETS_PER_BYTE, (char *) 0);
*p = 0;
if (blocking_flag)
flags |= SEC_TIC54X_BLOCK;
if (!bfd_set_section_flags (stdoutput, seg, flags))
as_warn ("Error setting flags for \"%s\": %s", name,
bfd_errmsg (bfd_get_error ()));
subseg_set (current_seg, current_subseg);
demand_empty_rest_of_line ();
}
static enum cpu_version
lookup_version (ver)
const char *ver;
{
enum cpu_version version = VNONE;
if (ver[0] == '5' && ver[1] == '4')
{
if (strlen (ver) == 3
&& (ver[2] == '1' || ver[2] == '2' || ver[2] == '3'
|| ver[2] == '5' || ver[2] == '8' || ver[2] == '9'))
version = ver[2] - '0';
else if (strlen (ver) == 5
&& TOUPPER (ver[3]) == 'L'
&& TOUPPER (ver[4]) == 'P'
&& (ver[2] == '5' || ver[2] == '6'))
version = ver[2] - '0' + 10;
}
return version;
}
static void
set_cpu (version)
enum cpu_version version;
{
cpu = version;
if (version == V545LP || version == V546LP)
{
symbolS *symbolP = symbol_new ("__allow_lp", absolute_section,
(valueT) 1, &zero_address_frag);
SF_SET_LOCAL (symbolP);
symbol_table_insert (symbolP);
}
}
static int cpu_needs_set = 1;
static void
tic54x_version (x)
int x ATTRIBUTE_UNUSED;
{
enum cpu_version version = VNONE;
enum cpu_version old_version = cpu;
int c;
char *ver;
ILLEGAL_WITHIN_STRUCT ();
SKIP_WHITESPACE ();
ver = input_line_pointer;
while (!is_end_of_line[(int) *input_line_pointer])
++input_line_pointer;
c = *input_line_pointer;
*input_line_pointer = 0;
version = lookup_version (ver);
if (cpu != VNONE && cpu != version)
as_warn (_("CPU version has already been set"));
if (version == VNONE)
{
as_bad (_("Unrecognized version '%s'"), ver);
ignore_rest_of_line ();
return;
}
else if (assembly_begun && version != old_version)
{
as_bad (_("Changing of CPU version on the fly not supported"));
ignore_rest_of_line ();
return;
}
set_cpu (version);
*input_line_pointer = c;
demand_empty_rest_of_line ();
}
static void
tic54x_float_cons (type)
int type;
{
if (current_stag != 0)
tic54x_struct_field ('f');
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
if (type != 'x')
{
frag_align (2, 0, 2);
if (line_label != NULL)
{
symbol_set_frag (line_label, frag_now);
S_SET_VALUE (line_label, frag_now_fix ());
}
}
float_cons ('f');
}
static void
tic54x_stringer (type)
int type;
{
unsigned int c;
char *start;
int append_zero = type == 'S' || type == 'P';
int packed = type == 'p' || type == 'P';
int last_char = -1;
if (current_stag != NULL)
{
tic54x_struct_field ('*');
return;
}
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
c = ',';
while (c == ',')
{
SKIP_WHITESPACE ();
switch (*input_line_pointer)
{
default:
{
unsigned short value = get_absolute_expression ();
FRAG_APPEND_1_CHAR ( value & 0xFF);
FRAG_APPEND_1_CHAR ((value >> 8) & 0xFF);
break;
}
case '\"':
++input_line_pointer;
start = input_line_pointer;
while (is_a_char (c = next_char_of_string ()))
{
if (!packed)
{
FRAG_APPEND_1_CHAR (c);
FRAG_APPEND_1_CHAR (0);
}
else
{
if (last_char == -1)
last_char = c;
else
{
FRAG_APPEND_1_CHAR (c);
FRAG_APPEND_1_CHAR (last_char);
last_char = -1;
}
}
}
if (append_zero)
{
if (packed && last_char != -1)
{
FRAG_APPEND_1_CHAR (0);
FRAG_APPEND_1_CHAR (last_char);
last_char = -1;
}
else
{
FRAG_APPEND_1_CHAR (0);
FRAG_APPEND_1_CHAR (0);
}
}
know (input_line_pointer[-1] == '\"');
break;
}
SKIP_WHITESPACE ();
c = *input_line_pointer;
if (!is_end_of_line[c])
++input_line_pointer;
}
if (packed && last_char != -1)
{
FRAG_APPEND_1_CHAR (0);
FRAG_APPEND_1_CHAR (last_char);
}
demand_empty_rest_of_line ();
}
static void
tic54x_p2align (arg)
int arg ATTRIBUTE_UNUSED;
{
as_bad (_("p2align not supported on this target"));
}
static void
tic54x_align_words (arg)
int arg;
{
int count = arg;
if (!is_end_of_line[(int) *input_line_pointer])
{
if (arg == 2)
as_warn (_("Argument to .even ignored"));
else
count = get_absolute_expression ();
}
if (current_stag != NULL && arg == 128)
{
if (current_stag->current_bitfield_offset != 0)
{
current_stag->current_bitfield_offset = 0;
++abs_section_offset;
}
demand_empty_rest_of_line ();
return;
}
ILLEGAL_WITHIN_STRUCT ();
s_align_bytes (count << 1);
}
static void
tic54x_field (ignore)
int ignore ATTRIBUTE_UNUSED;
{
expressionS exp;
int size = 16;
char *p;
valueT value;
symbolS *label = line_label;
if (current_stag != NULL)
{
tic54x_struct_field ('.');
return;
}
input_line_pointer = parse_expression (input_line_pointer, &exp);
if (*input_line_pointer == ',')
{
++input_line_pointer;
size = get_absolute_expression ();
if (size < 1 || size > 32)
{
as_bad (_("Invalid field size, must be from 1 to 32"));
ignore_rest_of_line ();
return;
}
}
if (exp.X_op != O_constant)
{
if (size != 16)
{
as_bad (_("field size must be 16 when value is relocatable"));
ignore_rest_of_line ();
return;
}
frag_now->tc_frag_data = 0;
emit_expr (&exp, 2);
}
else
{
unsigned long fmask = (size == 32) ? 0xFFFFFFFF : (1ul << size) - 1;
value = exp.X_add_number;
exp.X_add_number &= fmask;
if (value != (valueT) exp.X_add_number)
as_warn (_("field value truncated"));
value = exp.X_add_number;
while (size >= 16)
{
frag_now->tc_frag_data = 0;
p = frag_more (2);
md_number_to_chars (p, (value >> (size - 16)) & 0xFFFF, 2);
size -= 16;
}
if (size > 0)
{
int bit_offset = frag_bit_offset (frag_now, now_seg);
fragS *alloc_frag = bit_offset_frag (frag_now, now_seg);
if (bit_offset == -1)
{
struct bit_info *bi = xmalloc (sizeof (struct bit_info));
expressionS size_exp;
size_exp.X_op = O_constant;
size_exp.X_add_number = size;
bi->seg = now_seg;
bi->type = TYPE_FIELD;
bi->value = value;
p = frag_var (rs_machine_dependent,
4, 1, (relax_substateT) 0,
make_expr_symbol (&size_exp), (offsetT) 0,
(char *) bi);
goto getout;
}
else if (bit_offset == 0 || bit_offset + size > 16)
{
p = frag_more (2);
frag_now->tc_frag_data = 0;
alloc_frag = frag_now;
}
else
{
p = alloc_frag == frag_now ?
frag_now->fr_literal + frag_now_fix_octets () - 2 :
alloc_frag->fr_literal;
if (label != NULL)
{
symbol_set_frag (label, alloc_frag);
if (alloc_frag == frag_now)
S_SET_VALUE (label, frag_now_fix () - 1);
label = NULL;
}
}
value <<= 16 - alloc_frag->tc_frag_data - size;
if (alloc_frag->tc_frag_data)
value |= ((unsigned short) p[1] << 8) | p[0];
md_number_to_chars (p, value, 2);
alloc_frag->tc_frag_data += size;
if (alloc_frag->tc_frag_data == 16)
alloc_frag->tc_frag_data = 0;
}
}
getout:
demand_empty_rest_of_line ();
}
static int
tic54x_initialized_section (seg)
segT seg;
{
return !seg_info (seg)->bss;
}
static void
tic54x_clink (ignored)
int ignored ATTRIBUTE_UNUSED;
{
segT seg = now_seg;
ILLEGAL_WITHIN_STRUCT ();
if (*input_line_pointer == '\"')
{
char *section_name = ++input_line_pointer;
char *name;
while (is_a_char (next_char_of_string ()))
;
know (input_line_pointer[-1] == '\"');
input_line_pointer[-1] = 0;
name = xmalloc (input_line_pointer - section_name + 1);
strcpy (name, section_name);
seg = bfd_get_section_by_name (stdoutput, name);
if (seg == NULL)
{
as_bad (_("Unrecognized section '%s'"), section_name);
ignore_rest_of_line ();
return;
}
}
else
{
if (!tic54x_initialized_section (seg))
{
as_bad (_("Current section is unitialized, "
"section name required for .clink"));
ignore_rest_of_line ();
return;
}
}
seg->flags |= SEC_TIC54X_CLINK;
demand_empty_rest_of_line ();
}
static void
tic54x_set_default_include (dot)
int dot;
{
char *dir = ".";
char *tmp = NULL;
if (!dot)
{
char *curfile;
unsigned lineno;
as_where (&curfile, &lineno);
dir = strcpy (xmalloc (strlen (curfile) + 1), curfile);
tmp = strrchr (dir, '/');
}
if (tmp != NULL)
{
int len;
*tmp = '\0';
len = strlen (dir);
if (include_dir_count == 0)
{
include_dirs = (char **) xmalloc (sizeof (*include_dirs));
include_dir_count = 1;
}
include_dirs[0] = dir;
if (len > include_dir_maxlen)
include_dir_maxlen = len;
}
else if (include_dirs != NULL)
include_dirs[0] = ".";
}
static void
tic54x_include (ignored)
int ignored ATTRIBUTE_UNUSED;
{
char newblock[] = " .newblock\n";
char *filename;
char *input;
int len, c = -1;
ILLEGAL_WITHIN_STRUCT ();
SKIP_WHITESPACE ();
if (*input_line_pointer == '"')
{
filename = demand_copy_C_string (&len);
demand_empty_rest_of_line ();
}
else
{
filename = input_line_pointer;
while (!is_end_of_line[(int) *input_line_pointer])
++input_line_pointer;
c = *input_line_pointer;
*input_line_pointer = '\0';
filename = strcpy (xmalloc (strlen (filename) + 1), filename);
*input_line_pointer = c;
demand_empty_rest_of_line ();
}
input = xmalloc (sizeof (newblock) + strlen (filename) + 4);
sprintf (input, "\"%s\"\n%s", filename, newblock);
input_scrub_insert_line (input);
tic54x_clear_local_labels (0);
tic54x_set_default_include (0);
s_include (0);
}
static void
tic54x_message (type)
int type;
{
char *msg;
char c;
int len;
ILLEGAL_WITHIN_STRUCT ();
if (*input_line_pointer == '"')
msg = demand_copy_C_string (&len);
else
{
msg = input_line_pointer;
while (!is_end_of_line[(int) *input_line_pointer])
++input_line_pointer;
c = *input_line_pointer;
*input_line_pointer = 0;
msg = strcpy (xmalloc (strlen (msg) + 1), msg);
*input_line_pointer = c;
}
switch (type)
{
case 'm':
as_tsktsk ("%s", msg);
break;
case 'w':
as_warn ("%s", msg);
break;
case 'e':
as_bad ("%s", msg);
break;
}
demand_empty_rest_of_line ();
}
static void
tic54x_label (ignored)
int ignored ATTRIBUTE_UNUSED;
{
char *name = input_line_pointer;
symbolS *symbolP;
int c;
ILLEGAL_WITHIN_STRUCT ();
c = get_symbol_end ();
symbolP = colon (name);
S_SET_STORAGE_CLASS (symbolP, C_STATLAB);
*input_line_pointer = c;
demand_empty_rest_of_line ();
}
static void
tic54x_mmregs (ignored)
int ignored ATTRIBUTE_UNUSED;
{
symbol *sym;
ILLEGAL_WITHIN_STRUCT ();
for (sym = (symbol *) mmregs; sym->name; sym++)
{
symbolS *symbolP = symbol_new (sym->name, absolute_section,
(valueT) sym->value, &zero_address_frag);
SF_SET_LOCAL (symbolP);
symbol_table_insert (symbolP);
}
}
static void
tic54x_loop (count)
int count;
{
ILLEGAL_WITHIN_STRUCT ();
SKIP_WHITESPACE ();
if (!is_end_of_line[(int) *input_line_pointer])
count = get_absolute_expression ();
do_repeat (count, "LOOP", "ENDLOOP");
}
static void
tic54x_endloop (ignore)
int ignore ATTRIBUTE_UNUSED;
{
as_bad (_("ENDLOOP without corresponding LOOP"));
ignore_rest_of_line ();
}
static void
tic54x_break (ignore)
int ignore ATTRIBUTE_UNUSED;
{
int cond = 1;
ILLEGAL_WITHIN_STRUCT ();
SKIP_WHITESPACE ();
if (!is_end_of_line[(int) *input_line_pointer])
cond = get_absolute_expression ();
if (cond)
end_repeat (substitution_line ? 1 : 0);
}
static void
set_address_mode (mode)
int mode;
{
amode = mode;
if (mode == far_mode)
{
symbolS *symbolP = symbol_new ("__allow_far", absolute_section,
(valueT) 1, &zero_address_frag);
SF_SET_LOCAL (symbolP);
symbol_table_insert (symbolP);
}
}
static int address_mode_needs_set = 1;
static void
tic54x_address_mode (mode)
int mode;
{
if (assembly_begun && amode != (unsigned) mode)
{
as_bad (_("Mixing of normal and extended addressing not supported"));
ignore_rest_of_line ();
return;
}
if (mode == far_mode && cpu != VNONE && cpu != V548 && cpu != V549)
{
as_bad (_("Extended addressing not supported on the specified CPU"));
ignore_rest_of_line ();
return;
}
set_address_mode (mode);
demand_empty_rest_of_line ();
}
static void
tic54x_sblock (ignore)
int ignore ATTRIBUTE_UNUSED;
{
int c = ',';
ILLEGAL_WITHIN_STRUCT ();
while (c == ',')
{
segT seg;
char *name;
if (*input_line_pointer == '"')
{
int len;
name = demand_copy_C_string (&len);
}
else
{
char *section_name = input_line_pointer;
c = get_symbol_end ();
name = xmalloc (strlen (section_name) + 1);
strcpy (name, section_name);
*input_line_pointer = c;
}
seg = bfd_get_section_by_name (stdoutput, name);
if (seg == NULL)
{
as_bad (_("Unrecognized section '%s'"), name);
ignore_rest_of_line ();
return;
}
else if (!tic54x_initialized_section (seg))
{
as_bad (_(".sblock may be used for initialized sections only"));
ignore_rest_of_line ();
return;
}
seg->flags |= SEC_TIC54X_BLOCK;
c = *input_line_pointer;
if (!is_end_of_line[(int) c])
++input_line_pointer;
}
demand_empty_rest_of_line ();
}
static void
tic54x_set (ignore)
int ignore ATTRIBUTE_UNUSED;
{
symbolS *symbolP;
char *name;
ILLEGAL_WITHIN_STRUCT ();
if (!line_label)
{
as_bad (_("Symbol missing for .set/.equ"));
ignore_rest_of_line ();
return;
}
name = xstrdup (S_GET_NAME (line_label));
line_label = NULL;
if ((symbolP = symbol_find (name)) == NULL
&& (symbolP = md_undefined_symbol (name)) == NULL)
{
symbolP = symbol_new (name, absolute_section, 0, &zero_address_frag);
S_SET_STORAGE_CLASS (symbolP, C_STAT);
}
free (name);
S_SET_DATA_TYPE (symbolP, T_INT);
S_SET_SEGMENT (symbolP, absolute_section);
symbol_table_insert (symbolP);
pseudo_set (symbolP);
demand_empty_rest_of_line ();
}
static void
tic54x_fclist (show)
int show;
{
if (show)
listing &= ~LISTING_NOCOND;
else
listing |= LISTING_NOCOND;
demand_empty_rest_of_line ();
}
static void
tic54x_sslist (show)
int show;
{
ILLEGAL_WITHIN_STRUCT ();
listing_sslist = show;
}
static void
tic54x_var (ignore)
int ignore ATTRIBUTE_UNUSED;
{
static char empty[] = "";
char *name;
int c;
ILLEGAL_WITHIN_STRUCT ();
if (macro_level == 0)
{
as_bad (_(".var may only be used within a macro definition"));
ignore_rest_of_line ();
return;
}
do
{
if (!ISALPHA (*input_line_pointer))
{
as_bad (_("Substitution symbols must begin with a letter"));
ignore_rest_of_line ();
return;
}
name = input_line_pointer;
c = get_symbol_end ();
name = strcpy (xmalloc (strlen (name) + 1), name);
hash_insert (subsym_hash[macro_level], name, empty);
*input_line_pointer = c;
if (c == ',')
{
++input_line_pointer;
if (is_end_of_line[(int) *input_line_pointer])
c = *input_line_pointer;
}
}
while (c == ',');
demand_empty_rest_of_line ();
}
static void
tic54x_mlib (ignore)
int ignore ATTRIBUTE_UNUSED;
{
char *filename;
char *path;
int len, i;
bfd *abfd, *mbfd;
ILLEGAL_WITHIN_STRUCT ();
if (*input_line_pointer == '"')
{
if ((filename = demand_copy_C_string (&len)) == NULL)
return;
}
else
{
SKIP_WHITESPACE ();
len = 0;
while (!is_end_of_line[(int) *input_line_pointer]
&& !ISSPACE (*input_line_pointer))
{
obstack_1grow (¬es, *input_line_pointer);
++input_line_pointer;
++len;
}
obstack_1grow (¬es, '\0');
filename = obstack_finish (¬es);
}
demand_empty_rest_of_line ();
tic54x_set_default_include (0);
path = xmalloc ((unsigned long) len + include_dir_maxlen + 5);
for (i = 0; i < include_dir_count; i++)
{
FILE *try;
strcpy (path, include_dirs[i]);
strcat (path, "/");
strcat (path, filename);
if ((try = fopen (path, "r")) != NULL)
{
fclose (try);
break;
}
}
if (i >= include_dir_count)
{
free (path);
path = filename;
}
register_dependency (path);
abfd = bfd_openr (path, NULL);
if (!abfd)
{
as_bad (_("Can't open macro library file '%s' for reading."), path);
as_perror ("%s", path);
ignore_rest_of_line ();
return;
}
if (!bfd_check_format (abfd, bfd_archive))
{
as_bad (_("File '%s' not in macro archive format"), path);
ignore_rest_of_line ();
return;
}
for (mbfd = bfd_openr_next_archived_file (abfd, NULL);
mbfd != NULL; mbfd = bfd_openr_next_archived_file (abfd, mbfd))
{
bfd_size_type size = bfd_get_size (mbfd);
char *buf = xmalloc (size);
char *fname = tmpnam (NULL);
FILE *ftmp;
bfd_bread (buf, size, mbfd);
ftmp = fopen (fname, "w+b");
fwrite ((void *) buf, size, 1, ftmp);
if (buf[size - 1] != '\n')
fwrite ("\n", 1, 1, ftmp);
fclose (ftmp);
free (buf);
input_scrub_insert_file (fname);
unlink (fname);
}
}
const pseudo_typeS md_pseudo_table[] =
{
{ "algebraic", s_ignore , 0 },
{ "align" , tic54x_align_words , 128 },
{ "ascii" , tic54x_stringer , 'p' },
{ "asciz" , tic54x_stringer , 'P' },
{ "even" , tic54x_align_words , 2 },
{ "asg" , tic54x_asg , 0 },
{ "eval" , tic54x_eval , 0 },
{ "bss" , tic54x_bss , 0 },
{ "byte" , tic54x_cons , 'b' },
{ "ubyte" , tic54x_cons , 'B' },
{ "char" , tic54x_cons , 'c' },
{ "uchar" , tic54x_cons , 'C' },
{ "clink" , tic54x_clink , 0 },
{ "c_mode" , tic54x_address_mode , c_mode },
{ "copy" , tic54x_include , 'c' },
{ "include" , tic54x_include , 'i' },
{ "data" , tic54x_sect , 'd' },
{ "double" , tic54x_float_cons , 'd' },
{ "ldouble" , tic54x_float_cons , 'l' },
{ "drlist" , s_ignore , 0 },
{ "drnolist" , s_ignore , 0 },
{ "emsg" , tic54x_message , 'e' },
{ "mmsg" , tic54x_message , 'm' },
{ "wmsg" , tic54x_message , 'w' },
{ "far_mode" , tic54x_address_mode , far_mode },
{ "fclist" , tic54x_fclist , 1 },
{ "fcnolist" , tic54x_fclist , 0 },
{ "field" , tic54x_field , -1 },
{ "float" , tic54x_float_cons , 'f' },
{ "xfloat" , tic54x_float_cons , 'x' },
{ "global" , tic54x_global , 'g' },
{ "def" , tic54x_global , 'd' },
{ "ref" , tic54x_global , 'r' },
{ "half" , tic54x_cons , 'h' },
{ "uhalf" , tic54x_cons , 'H' },
{ "short" , tic54x_cons , 's' },
{ "ushort" , tic54x_cons , 'S' },
{ "if" , s_if , (int) O_ne },
{ "elseif" , s_elseif , (int) O_ne },
{ "else" , s_else , 0 },
{ "endif" , s_endif , 0 },
{ "int" , tic54x_cons , 'i' },
{ "uint" , tic54x_cons , 'I' },
{ "word" , tic54x_cons , 'w' },
{ "uword" , tic54x_cons , 'W' },
{ "label" , tic54x_label , 0 },
{ "length" , s_ignore , 0 },
{ "width" , s_ignore , 0 },
{ "long" , tic54x_cons , 'l' },
{ "ulong" , tic54x_cons , 'L' },
{ "xlong" , tic54x_cons , 'x' },
{ "loop" , tic54x_loop , 1024 },
{ "break" , tic54x_break , 0 },
{ "endloop" , tic54x_endloop , 0 },
{ "mlib" , tic54x_mlib , 0 },
{ "mlist" , s_ignore , 0 },
{ "mnolist" , s_ignore , 0 },
{ "mmregs" , tic54x_mmregs , 0 },
{ "newblock" , tic54x_clear_local_labels, 0 },
{ "option" , s_ignore , 0 },
{ "p2align" , tic54x_p2align , 0 },
{ "sblock" , tic54x_sblock , 0 },
{ "sect" , tic54x_sect , '*' },
{ "set" , tic54x_set , 0 },
{ "equ" , tic54x_set , 0 },
{ "space" , tic54x_space , 0 },
{ "bes" , tic54x_space , 1 },
{ "sslist" , tic54x_sslist , 1 },
{ "ssnolist" , tic54x_sslist , 0 },
{ "string" , tic54x_stringer , 's' },
{ "pstring" , tic54x_stringer , 'p' },
{ "struct" , tic54x_struct , 0 },
{ "tag" , tic54x_tag , 0 },
{ "endstruct", tic54x_endstruct , 0 },
{ "tab" , s_ignore , 0 },
{ "text" , tic54x_sect , 't' },
{ "union" , tic54x_struct , 1 },
{ "endunion" , tic54x_endstruct , 1 },
{ "usect" , tic54x_usect , 0 },
{ "var" , tic54x_var , 0 },
{ "version" , tic54x_version , 0 },
{0 , 0 , 0 }
};
int
md_parse_option (c, arg)
int c;
char *arg;
{
switch (c)
{
default:
return 0;
case OPTION_COFF_VERSION:
{
int version = atoi (arg);
if (version != 0 && version != 1 && version != 2)
as_fatal (_("Bad COFF version '%s'"), arg);
break;
}
case OPTION_CPU_VERSION:
{
cpu = lookup_version (arg);
cpu_needs_set = 1;
if (cpu == VNONE)
as_fatal (_("Bad CPU version '%s'"), arg);
break;
}
case OPTION_ADDRESS_MODE:
amode = far_mode;
address_mode_needs_set = 1;
break;
case OPTION_STDERR_TO_FILE:
{
char *filename = arg;
FILE *fp = fopen (filename, "w+");
if (fp == NULL)
as_fatal (_("Can't redirect stderr to the file '%s'"), filename);
fclose (fp);
if ((fp = freopen (filename, "w+", stderr)) == NULL)
as_fatal (_("Can't redirect stderr to the file '%s'"), filename);
break;
}
}
return 1;
}
void
tic54x_macro_start ()
{
++macro_level;
subsym_hash[macro_level] = hash_new ();
local_label_hash[macro_level] = hash_new ();
}
void
tic54x_macro_info (info)
void *info;
{
struct formal_struct
{
struct formal_struct *next;
sb name;
sb def;
sb actual;
int index;
} *entry;
struct macro_struct
{
sb sub;
int formal_count;
struct formal_struct *formals;
struct hash_control *formal_hash;
} *macro;
macro = (struct macro_struct *) info;
for (entry = macro->formals; entry; entry = entry->next)
{
char *name = strncpy (xmalloc (entry->name.len + 1),
entry->name.ptr, entry->name.len);
char *value = strncpy (xmalloc (entry->actual.len + 1),
entry->actual.ptr, entry->actual.len);
name[entry->name.len] = '\0';
value[entry->actual.len] = '\0';
hash_insert (subsym_hash[macro_level], name, value);
}
}
void
tic54x_macro_end ()
{
hash_die (subsym_hash[macro_level]);
subsym_hash[macro_level] = NULL;
hash_die (local_label_hash[macro_level]);
local_label_hash[macro_level] = NULL;
--macro_level;
}
static int
subsym_symlen (a, ignore)
char *a;
char *ignore ATTRIBUTE_UNUSED;
{
return strlen (a);
}
static int
subsym_symcmp (a, b)
char *a;
char *b;
{
return strcmp (a, b);
}
static int
subsym_firstch (a, b)
char *a;
char *b;
{
int val = atoi (b);
char *tmp = strchr (a, val);
return tmp ? tmp - a + 1 : 0;
}
static int
subsym_lastch (a, b)
char *a;
char *b;
{
int val = atoi (b);
char *tmp = strrchr (a, val);
return tmp ? tmp - a + 1 : 0;
}
static int
subsym_isdefed (a, ignore)
char *a;
char *ignore ATTRIBUTE_UNUSED;
{
symbolS *symbolP = symbol_find (a);
return symbolP != NULL;
}
static int
subsym_ismember (sym, list)
char *sym;
char *list;
{
char *elem, *ptr, *listv;
if (!list)
return 0;
listv = subsym_lookup (list, macro_level);
if (!listv)
{
as_bad (_("Undefined substitution symbol '%s'"), list);
ignore_rest_of_line ();
return 0;
}
ptr = elem = xmalloc (strlen (listv) + 1);
strcpy (elem, listv);
while (*ptr && *ptr != ',')
++ptr;
*ptr++ = 0;
subsym_create_or_replace (sym, elem);
subsym_create_or_replace (list, ptr);
return *list != 0;
}
static int
subsym_iscons (a, ignore)
char *a;
char *ignore ATTRIBUTE_UNUSED;
{
expressionS exp;
parse_expression (a, &exp);
if (exp.X_op == O_constant)
{
int len = strlen (a);
switch (TOUPPER (a[len - 1]))
{
case 'B':
return 1;
case 'Q':
return 2;
case 'H':
return 3;
case '\'':
return 4;
default:
break;
}
if (*a == '0' && len > 1)
{
if (TOUPPER (a[1]) == 'X')
return 3;
return 2;
}
return 5;
}
return 0;
}
static int
subsym_isname (a, ignore)
char *a;
char *ignore ATTRIBUTE_UNUSED;
{
if (!is_name_beginner (*a))
return 0;
while (*a)
{
if (!is_part_of_name (*a))
return 0;
++a;
}
return 1;
}
static int
subsym_isreg (a, ignore)
char *a;
char *ignore ATTRIBUTE_UNUSED;
{
if (hash_find (reg_hash, a))
return 1;
if (hash_find (mmreg_hash, a))
return 1;
return 0;
}
static int
subsym_structsz (name, ignore)
char *name;
char *ignore ATTRIBUTE_UNUSED;
{
struct stag *stag = (struct stag *) hash_find (stag_hash, name);
if (stag)
return stag->size;
return 0;
}
static int
subsym_structacc (stag_name, ignore)
char *stag_name ATTRIBUTE_UNUSED;
char *ignore ATTRIBUTE_UNUSED;
{
return 0;
}
static float
math_ceil (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) ceil (arg1);
}
static float
math_cvi (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (int) arg1;
}
static float
math_floor (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) floor (arg1);
}
static float
math_fmod (arg1, arg2)
float arg1;
float arg2;
{
return (int) arg1 % (int) arg2;
}
static float
math_int (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return ((float) ((int) arg1)) == arg1;
}
static float
math_round (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5);
}
static float
math_sgn (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (arg1 < 0) ? -1 : (arg1 ? 1 : 0);
}
static float
math_trunc (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (int) arg1;
}
static float
math_acos (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) acos (arg1);
}
static float
math_asin (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) asin (arg1);
}
static float
math_atan (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) atan (arg1);
}
static float
math_atan2 (arg1, arg2)
float arg1;
float arg2;
{
return (float) atan2 (arg1, arg2);
}
static float
math_cosh (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) cosh (arg1);
}
static float
math_cos (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) cos (arg1);
}
static float
math_cvf (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) arg1;
}
static float
math_exp (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) exp (arg1);
}
static float
math_fabs (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) fabs (arg1);
}
static float
math_ldexp (arg1, arg2)
float arg1;
float arg2;
{
return arg1 * (float) pow (2.0, arg2);
}
static float
math_log10 (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) log10 (arg1);
}
static float
math_log (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) log (arg1);
}
static float
math_max (arg1, arg2)
float arg1;
float arg2;
{
return (arg1 > arg2) ? arg1 : arg2;
}
static float
math_min (arg1, arg2)
float arg1;
float arg2;
{
return (arg1 < arg2) ? arg1 : arg2;
}
static float
math_pow (arg1, arg2)
float arg1;
float arg2;
{
return (float) pow (arg1, arg2);
}
static float
math_sin (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) sin (arg1);
}
static float
math_sinh (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) sinh (arg1);
}
static float
math_sqrt (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) sqrt (arg1);
}
static float
math_tan (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) tan (arg1);
}
static float
math_tanh (arg1, ignore)
float arg1;
float ignore ATTRIBUTE_UNUSED;
{
return (float) tanh (arg1);
}
typedef struct
{
char *name;
int (*proc) PARAMS ((char *, char *));
int nargs;
} subsym_proc_entry;
static const subsym_proc_entry subsym_procs[] =
{
{ "$symlen", subsym_symlen, 1, },
{ "$symcmp", subsym_symcmp, 2, },
{ "$firstch", subsym_firstch, 2, },
{ "$lastch", subsym_lastch, 2, },
{ "$isdefed", subsym_isdefed, 1, },
{ "$ismember", subsym_ismember, 2, },
{ "$iscons", subsym_iscons, 1, },
{ "$isname", subsym_isname, 1, },
{ "$isreg", subsym_isreg, 1, },
{ "$structsz", subsym_structsz, 1, },
{ "$structacc", subsym_structacc, 1, },
{ NULL, NULL, 0 },
};
typedef struct
{
char *name;
float (*proc) PARAMS ((float, float));
int nargs;
int int_return;
} math_proc_entry;
static const math_proc_entry math_procs[] =
{
{ "$cvi", math_cvi, 1, 1 },
{ "$int", math_int, 1, 1 },
{ "$sgn", math_sgn, 1, 1 },
{ "$acos", math_acos, 1, 0 },
{ "$asin", math_asin, 1, 0 },
{ "$atan", math_atan, 1, 0 },
{ "$atan2", math_atan2, 2, 0 },
{ "$ceil", math_ceil, 1, 0 },
{ "$cosh", math_cosh, 1, 0 },
{ "$cos", math_cos, 1, 0 },
{ "$cvf", math_cvf, 1, 0 },
{ "$exp", math_exp, 1, 0 },
{ "$fabs", math_fabs, 1, 0 },
{ "$floor", math_floor, 1, 0 },
{ "$fmod", math_fmod, 2, 0 },
{ "$ldexp", math_ldexp, 2, 0 },
{ "$log10", math_log10, 1, 0 },
{ "$log", math_log, 1, 0 },
{ "$max", math_max, 2, 0 },
{ "$min", math_min, 2, 0 },
{ "$pow", math_pow, 2, 0 },
{ "$round", math_round, 1, 0 },
{ "$sin", math_sin, 1, 0 },
{ "$sinh", math_sinh, 1, 0 },
{ "$sqrt", math_sqrt, 1, 0 },
{ "$tan", math_tan, 1, 0 },
{ "$tanh", math_tanh, 1, 0 },
{ "$trunc", math_trunc, 1, 0 },
{ NULL, NULL, 0, 0 },
};
void
md_begin ()
{
template *tm;
symbol *sym;
const subsym_proc_entry *subsym_proc;
const math_proc_entry *math_proc;
const char *hash_err;
char **symname;
char *TIC54X_DIR = getenv ("TIC54X_DIR");
char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR");
local_label_id = 0;
if (A_DIR != NULL)
{
char *tmp = xstrdup (A_DIR);
do
{
char *next = strchr (tmp, ';');
if (next)
*next++ = '\0';
add_include_dir (tmp);
tmp = next;
}
while (tmp != NULL);
}
op_hash = hash_new ();
for (tm = (template *) tic54x_optab; tm->name; tm++)
{
if (hash_find (op_hash, tm->name))
continue;
hash_err = hash_insert (op_hash, tm->name, (char *) tm);
if (hash_err)
as_fatal ("Internal Error: Can't hash %s: %s",
tm->name, hash_err);
}
parop_hash = hash_new ();
for (tm = (template *) tic54x_paroptab; tm->name; tm++)
{
if (hash_find (parop_hash, tm->name))
continue;
hash_err = hash_insert (parop_hash, tm->name, (char *) tm);
if (hash_err)
as_fatal ("Internal Error: Can't hash %s: %s",
tm->name, hash_err);
}
reg_hash = hash_new ();
for (sym = (symbol *) regs; sym->name; sym++)
{
symbolS *symbolP = symbol_new (sym->name, absolute_section,
(valueT) sym->value, &zero_address_frag);
SF_SET_LOCAL (symbolP);
symbol_table_insert (symbolP);
hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
}
for (sym = (symbol *) mmregs; sym->name; sym++)
hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
mmreg_hash = hash_new ();
for (sym = (symbol *) mmregs; sym->name; sym++)
hash_err = hash_insert (mmreg_hash, sym->name, (char *) sym);
cc_hash = hash_new ();
for (sym = (symbol *) condition_codes; sym->name; sym++)
hash_err = hash_insert (cc_hash, sym->name, (char *) sym);
cc2_hash = hash_new ();
for (sym = (symbol *) cc2_codes; sym->name; sym++)
hash_err = hash_insert (cc2_hash, sym->name, (char *) sym);
cc3_hash = hash_new ();
for (sym = (symbol *) cc3_codes; sym->name; sym++)
hash_err = hash_insert (cc3_hash, sym->name, (char *) sym);
sbit_hash = hash_new ();
for (sym = (symbol *) status_bits; sym->name; sym++)
hash_err = hash_insert (sbit_hash, sym->name, (char *) sym);
misc_symbol_hash = hash_new ();
for (symname = (char **) misc_symbols; *symname; symname++)
hash_err = hash_insert (misc_symbol_hash, *symname, *symname);
local_label_hash[0] = hash_new ();
subsym_hash[0] = hash_new ();
for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++)
hash_err = hash_insert (subsym_hash[0], subsym_proc->name,
(char *) subsym_proc);
math_hash = hash_new ();
for (math_proc = math_procs; math_proc->name; math_proc++)
{
hash_err = hash_insert (subsym_hash[0], math_proc->name,
(char *) math_proc);
hash_err = hash_insert (math_hash, math_proc->name,
(char *) math_proc);
}
subsym_recurse_hash = hash_new ();
stag_hash = hash_new ();
}
static int
is_accumulator (operand)
struct opstruct *operand;
{
return strcasecmp (operand->buf, "a") == 0
|| strcasecmp (operand->buf, "b") == 0;
}
static int
get_operands (operands, line)
struct opstruct operands[];
char *line;
{
char *lptr = line;
int numexp = 0;
int expecting_operand = 0;
int i;
while (numexp < MAX_OPERANDS && !is_end_of_line[(int) *lptr])
{
int paren_not_balanced = 0;
char *op_start, *op_end;
while (*lptr && ISSPACE (*lptr))
++lptr;
op_start = lptr;
while (paren_not_balanced || *lptr != ',')
{
if (*lptr == '\0')
{
if (paren_not_balanced)
{
as_bad ("Unbalanced parenthesis in operand %d", numexp);
return -1;
}
else
break;
}
if (*lptr == '(')
++paren_not_balanced;
else if (*lptr == ')')
--paren_not_balanced;
++lptr;
}
op_end = lptr;
if (op_end != op_start)
{
int len = op_end - op_start;
strncpy (operands[numexp].buf, op_start, len);
operands[numexp].buf[len] = 0;
while (len > 0 && ISSPACE (operands[numexp].buf[len - 1]))
operands[numexp].buf[--len] = 0;
lptr = op_end;
++numexp;
}
else
{
if (expecting_operand || *lptr == ',')
{
as_bad ("Expecting operand after ','");
return -1;
}
}
if (*lptr == ',')
{
if (*++lptr == '\0')
{
as_bad ("Expecting operand after ','");
return -1;
}
expecting_operand = 1;
}
}
while (*lptr && ISSPACE (*lptr++))
;
if (!is_end_of_line[(int) *lptr])
{
as_bad ("Extra junk on line");
return -1;
}
for (i = 0; i < numexp; i++)
{
memset (&operands[i].exp, 0, sizeof (operands[i].exp));
if (operands[i].buf[0] == '#')
{
parse_expression (operands[i].buf + 1, &operands[i].exp);
}
else if (operands[i].buf[0] == '@')
{
parse_expression (operands[i].buf + 1, &operands[i].exp);
}
else if (operands[i].buf[0] == '*')
{
char *paren = strchr (operands[i].buf, '(');
if (paren && paren[1] == '#')
*++paren = '(';
if (paren != NULL)
{
int len = strlen (paren);
char *end = paren + len;
int c;
while (end[-1] != ')')
if (--end <= paren)
{
as_bad (_("Badly formed address expression"));
return -1;
}
c = *end;
*end = '\0';
parse_expression (paren, &operands[i].exp);
*end = c;
}
else
operands[i].exp.X_op = O_absent;
}
else
parse_expression (operands[i].buf, &operands[i].exp);
}
return numexp;
}
static int
is_immediate (operand)
struct opstruct *operand;
{
return *operand->buf == '#';
}
static int
is_absolute (operand)
struct opstruct *operand;
{
return operand->exp.X_op == O_constant && !is_immediate (operand);
}
static int
is_indirect (operand)
struct opstruct *operand;
{
return operand->buf[0] == '*';
}
static int
is_dual (operand)
struct opstruct *operand;
{
if (is_indirect (operand) && strncasecmp (operand->buf, "*ar", 3) == 0)
{
char *tmp = operand->buf + 3;
int arf;
int valid_mod;
arf = *tmp++ - '0';
valid_mod = *tmp == '\0' ||
strcasecmp (tmp, "-") == 0 ||
strcasecmp (tmp, "+") == 0 ||
strcasecmp (tmp, "+0%") == 0;
return arf >= 2 && arf <= 5 && valid_mod;
}
return 0;
}
static int
is_mmreg (operand)
struct opstruct *operand;
{
return (is_absolute (operand)
|| is_immediate (operand)
|| hash_find (mmreg_hash, operand->buf) != 0);
}
static int
is_type (operand, type)
struct opstruct *operand;
enum optype type;
{
switch (type)
{
case OP_None:
return operand->buf[0] == 0;
case OP_Xmem:
case OP_Ymem:
return is_dual (operand);
case OP_Sind:
return is_indirect (operand);
case OP_xpmad_ms7:
return is_immediate (operand);
case OP_xpmad:
case OP_pmad:
case OP_PA:
case OP_dmad:
case OP_Lmem:
case OP_MMR:
return 1;
case OP_Smem:
return !is_immediate (operand);
case OP_MMRY:
case OP_MMRX:
return is_mmreg (operand);
case OP_SRC:
case OP_SRC1:
case OP_RND:
case OP_DST:
return is_accumulator (operand);
case OP_B:
return is_accumulator (operand) && TOUPPER (operand->buf[0]) == 'B';
case OP_A:
return is_accumulator (operand) && TOUPPER (operand->buf[0]) == 'A';
case OP_ARX:
return strncasecmp ("ar", operand->buf, 2) == 0
&& ISDIGIT (operand->buf[2]);
case OP_SBIT:
return hash_find (sbit_hash, operand->buf) != 0 || is_absolute (operand);
case OP_CC:
return hash_find (cc_hash, operand->buf) != 0;
case OP_CC2:
return hash_find (cc2_hash, operand->buf) != 0;
case OP_CC3:
return hash_find (cc3_hash, operand->buf) != 0
|| is_immediate (operand) || is_absolute (operand);
case OP_16:
return (is_immediate (operand) || is_absolute (operand))
&& operand->exp.X_add_number == 16;
case OP_N:
return is_absolute (operand) || is_immediate (operand) ||
strcasecmp ("st0", operand->buf) == 0 ||
strcasecmp ("st1", operand->buf) == 0;
case OP_12:
case OP_123:
return is_absolute (operand) || is_immediate (operand);
case OP_SHFT:
return (is_immediate (operand) || is_absolute (operand))
&& operand->exp.X_add_number >= 0 && operand->exp.X_add_number < 16;
case OP_SHIFT:
return (is_immediate (operand) || is_absolute (operand))
&& operand->exp.X_add_number != 16;
case OP_BITC:
case OP_031:
case OP_k8:
return is_absolute (operand) || is_immediate (operand);
case OP_k8u:
return is_immediate (operand)
&& operand->exp.X_op == O_constant
&& operand->exp.X_add_number >= 0
&& operand->exp.X_add_number < 256;
case OP_lk:
case OP_lku:
return 1;
case OP_k5:
case OP_k3:
case OP_k9:
return is_immediate (operand);
case OP_T:
return strcasecmp ("t", operand->buf) == 0 ||
strcasecmp ("treg", operand->buf) == 0;
case OP_TS:
return strcasecmp ("ts", operand->buf) == 0;
case OP_ASM:
return strcasecmp ("asm", operand->buf) == 0;
case OP_TRN:
return strcasecmp ("trn", operand->buf) == 0;
case OP_DP:
return strcasecmp ("dp", operand->buf) == 0;
case OP_ARP:
return strcasecmp ("arp", operand->buf) == 0;
default:
return 0;
}
}
static int
operands_match (insn, operands, opcount, refoptype, minops, maxops)
tic54x_insn *insn;
struct opstruct *operands;
int opcount;
const enum optype *refoptype;
int minops;
int maxops;
{
int op = 0, refop = 0;
if (opcount == 0 && minops == 0)
return 1;
while (op <= maxops && refop <= maxops)
{
while (!is_type (&operands[op], OPTYPE (refoptype[refop])))
{
if (refoptype[refop] & OPT)
{
++refop;
--maxops;
if (refop > maxops)
return 0;
}
else
return 0;
}
operands[op].type = OPTYPE (refoptype[refop]);
++refop;
++op;
if (op == opcount)
{
while (op < maxops)
{
if ((refoptype[refop] & OPT) == 0)
return 0;
if (OPTYPE (refoptype[refop]) == OP_DST)
insn->using_default_dst = 1;
++refop;
++op;
}
return 1;
}
}
return 0;
}
static int
encode_dmad (insn, operand, xpc_code)
tic54x_insn *insn;
struct opstruct *operand;
int xpc_code;
{
int op = 1 + insn->is_lkaddr;
if (is_indirect (operand) && operand->buf[strlen (operand->buf) - 1] != ')')
{
as_bad (_("Invalid dmad syntax '%s'"), operand->buf);
return 0;
}
insn->opcode[op].addr_expr = operand->exp;
if (insn->opcode[op].addr_expr.X_op == O_constant)
{
valueT value = insn->opcode[op].addr_expr.X_add_number;
if (xpc_code == 1)
{
insn->opcode[0].word &= 0xFF80;
insn->opcode[0].word |= (value >> 16) & 0x7F;
insn->opcode[1].word = value & 0xFFFF;
}
else if (xpc_code == 2)
insn->opcode[op].word = (value >> 16) & 0xFFFF;
else
insn->opcode[op].word = value;
}
else
{
insn->opcode[op].word = 0;
insn->opcode[op].r_nchars = 2;
if (amode == c_mode)
insn->opcode[op].r_type = BFD_RELOC_TIC54X_16_OF_23;
else if (xpc_code == 1)
{
insn->opcode[0].addr_expr = operand->exp;
insn->opcode[0].r_type = BFD_RELOC_TIC54X_23;
insn->opcode[0].r_nchars = 4;
insn->opcode[0].unresolved = 1;
insn->words = 1;
}
else if (xpc_code == 2)
insn->opcode[op].r_type = BFD_RELOC_TIC54X_MS7_OF_23;
else
insn->opcode[op].r_type = BFD_RELOC_TIC54X_16_OF_23;
insn->opcode[op].unresolved = 1;
}
return 1;
}
static int
encode_address (insn, operand)
tic54x_insn *insn;
struct opstruct *operand;
{
insn->opcode[0].addr_expr = operand->exp;
if (operand->exp.X_op == O_constant)
insn->opcode[0].word |= (operand->exp.X_add_number & 0x7F);
else
{
if (operand->exp.X_op == O_register)
as_bad (_("Use the .mmregs directive to use memory-mapped register names such as '%s'"), operand->buf);
insn->opcode[0].r_nchars = 1;
insn->opcode[0].r_type = BFD_RELOC_TIC54X_PARTLS7;
insn->opcode[0].unresolved = 1;
}
return 1;
}
static int
encode_indirect (insn, operand)
tic54x_insn *insn;
struct opstruct *operand;
{
int arf;
int mod;
if (insn->is_lkaddr)
{
mod = ((TOUPPER (operand->buf[1]) == 'A') ? 12 :
(operand->buf[1] == '(') ? 15 :
(strchr (operand->buf, '%') != NULL) ? 14 : 13);
arf = ((mod == 12) ? operand->buf[3] - '0' :
(mod == 15) ? 0 : operand->buf[4] - '0');
insn->opcode[1].addr_expr = operand->exp;
if (operand->exp.X_op == O_constant)
insn->opcode[1].word = operand->exp.X_add_number;
else
{
insn->opcode[1].word = 0;
insn->opcode[1].r_nchars = 2;
insn->opcode[1].r_type = BFD_RELOC_TIC54X_16_OF_23;
insn->opcode[1].unresolved = 1;
}
}
else if (strncasecmp (operand->buf, "*sp (", 4) == 0)
{
return encode_address (insn, operand);
}
else
{
arf = (TOUPPER (operand->buf[1]) == 'A' ?
operand->buf[3] : operand->buf[4]) - '0';
if (operand->buf[1] == '+')
{
mod = 3;
if (insn->tm->flags & FL_SMR)
as_warn (_("Address mode *+ARx is write-only. "
"Results of reading are undefined."));
}
else if (operand->buf[4] == '\0')
mod = 0;
else if (operand->buf[5] == '\0')
mod = (operand->buf[4] == '-' ? 1 : 2);
else if (operand->buf[6] == '\0')
{
if (operand->buf[5] == '0')
mod = (operand->buf[4] == '-' ? 5 : 6);
else
mod = (operand->buf[4] == '-' ? 8 : 10);
}
else if (TOUPPER (operand->buf[6]) == 'B')
mod = (operand->buf[4] == '-' ? 4 : 7);
else if (TOUPPER (operand->buf[6]) == '%')
mod = (operand->buf[4] == '-' ? 9 : 11);
else
{
as_bad (_("Unrecognized indirect address format \"%s\""),
operand->buf);
return 0;
}
}
insn->opcode[0].word |= 0x80 | (mod << 3) | arf;
return 1;
}
static int
encode_integer (insn, operand, which, min, max, mask)
tic54x_insn *insn;
struct opstruct *operand;
int which;
int min;
int max;
unsigned short mask;
{
long parse, integer;
insn->opcode[which].addr_expr = operand->exp;
if (operand->exp.X_op == O_constant)
{
parse = operand->exp.X_add_number;
if ((parse & 0x8000) && min == -32768 && max == 32767)
integer = (short) parse;
else
integer = parse;
if (integer >= min && integer <= max)
{
insn->opcode[which].word |= (integer & mask);
return 1;
}
as_bad (_("Operand '%s' out of range (%d <= x <= %d)"),
operand->buf, min, max);
}
else
{
if (insn->opcode[which].addr_expr.X_op == O_constant)
{
insn->opcode[which].word |=
insn->opcode[which].addr_expr.X_add_number & mask;
}
else
{
bfd_reloc_code_real_type rtype =
(mask == 0x1FF ? BFD_RELOC_TIC54X_PARTMS9 :
mask == 0xFFFF ? BFD_RELOC_TIC54X_16_OF_23 :
mask == 0x7F ? BFD_RELOC_TIC54X_PARTLS7 : BFD_RELOC_8);
int size = (mask == 0x1FF || mask == 0xFFFF) ? 2 : 1;
if (rtype == BFD_RELOC_8)
as_bad (_("Error in relocation handling"));
insn->opcode[which].r_nchars = size;
insn->opcode[which].r_type = rtype;
insn->opcode[which].unresolved = 1;
}
return 1;
}
return 0;
}
static int
encode_condition (insn, operand)
tic54x_insn *insn;
struct opstruct *operand;
{
symbol *cc = (symbol *) hash_find (cc_hash, operand->buf);
if (!cc)
{
as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
return 0;
}
#define CC_GROUP 0x40
#define CC_ACC 0x08
#define CATG_A1 0x07
#define CATG_B1 0x30
#define CATG_A2 0x30
#define CATG_B2 0x0C
#define CATG_C2 0x03
if (((insn->opcode[0].word & 0xFF) != 0))
{
if ((insn->opcode[0].word & CC_GROUP) != (cc->value & CC_GROUP))
{
as_bad (_("Condition \"%s\" does not match preceding group"),
operand->buf);
return 0;
}
if (insn->opcode[0].word & CC_GROUP)
{
if ((insn->opcode[0].word & CC_ACC) != (cc->value & CC_ACC))
{
as_bad (_("Condition \"%s\" uses a different accumulator from "
"a preceding condition"),
operand->buf);
return 0;
}
if ((insn->opcode[0].word & CATG_A1) && (cc->value & CATG_A1))
{
as_bad (_("Only one comparison conditional allowed"));
return 0;
}
if ((insn->opcode[0].word & CATG_B1) && (cc->value & CATG_B1))
{
as_bad (_("Only one overflow conditional allowed"));
return 0;
}
}
else if ( ((insn->opcode[0].word & CATG_A2) && (cc->value & CATG_A2))
|| ((insn->opcode[0].word & CATG_B2) && (cc->value & CATG_B2))
|| ((insn->opcode[0].word & CATG_C2) && (cc->value & CATG_C2)))
{
as_bad (_("Duplicate %s conditional"), operand->buf);
return 0;
}
}
insn->opcode[0].word |= cc->value;
return 1;
}
static int
encode_cc3 (insn, operand)
tic54x_insn *insn;
struct opstruct *operand;
{
symbol *cc3 = (symbol *) hash_find (cc3_hash, operand->buf);
int value = cc3 ? cc3->value : operand->exp.X_add_number << 8;
if ((value & 0x0300) != value)
{
as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
return 0;
}
insn->opcode[0].word |= value;
return 1;
}
static int
encode_arx (insn, operand)
tic54x_insn *insn;
struct opstruct *operand;
{
int arf = strlen (operand->buf) >= 3 ? operand->buf[2] - '0' : -1;
if (strncasecmp ("ar", operand->buf, 2) || arf < 0 || arf > 7)
{
as_bad (_("Invalid auxiliary register (use AR0-AR7)"));
return 0;
}
insn->opcode[0].word |= arf;
return 1;
}
static int
encode_cc2 (insn, operand)
tic54x_insn *insn;
struct opstruct *operand;
{
symbol *cc2 = (symbol *) hash_find (cc2_hash, operand->buf);
if (!cc2)
{
as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
return 0;
}
insn->opcode[0].word |= cc2->value;
return 1;
}
static int
encode_operand (insn, type, operand)
tic54x_insn *insn;
enum optype type;
struct opstruct *operand;
{
int ext = (insn->tm->flags & FL_EXT) != 0;
if (type == OP_MMR && operand->exp.X_op != O_constant)
{
if (insn->is_lkaddr)
{
as_bad (_("lk addressing modes are invalid for memory-mapped "
"register addressing"));
return 0;
}
type = OP_Smem;
if (strncasecmp (operand->buf, "*+ar", 4) == 0)
{
as_warn (_("Address mode *+ARx is not allowed in memory-mapped "
"register addressing. Resulting behavior is "
"undefined."));
}
}
switch (type)
{
case OP_None:
return 1;
case OP_dmad:
return encode_dmad (insn, operand, 0);
case OP_SRC:
if (TOUPPER (*operand->buf) == 'B')
{
insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 9);
if (insn->using_default_dst)
insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
}
return 1;
case OP_RND:
if (!((TOUPPER (operand->buf[0]) == 'B') ^
((insn->opcode[0].word & (1 << 8)) != 0)))
{
as_bad (_("Destination accumulator for each part of this parallel "
"instruction must be different"));
return 0;
}
return 1;
case OP_SRC1:
case OP_DST:
if (TOUPPER (operand->buf[0]) == 'B')
insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
return 1;
case OP_Xmem:
case OP_Ymem:
{
int mod = (operand->buf[4] == '\0' ? 0 :
operand->buf[4] == '-' ? 1 :
operand->buf[5] == '\0' ? 2 : 3);
int arf = operand->buf[3] - '0' - 2;
int code = (mod << 2) | arf;
insn->opcode[0].word |= (code << (type == OP_Xmem ? 4 : 0));
return 1;
}
case OP_Lmem:
case OP_Smem:
if (!is_indirect (operand))
return encode_address (insn, operand);
case OP_Sind:
return encode_indirect (insn, operand);
case OP_xpmad_ms7:
return encode_dmad (insn, operand, 2);
case OP_xpmad:
return encode_dmad (insn, operand, 1);
case OP_PA:
case OP_pmad:
return encode_dmad (insn, operand, 0);
case OP_ARX:
return encode_arx (insn, operand);
case OP_MMRX:
case OP_MMRY:
case OP_MMR:
{
int value = operand->exp.X_add_number;
if (type == OP_MMR)
insn->opcode[0].word |= value;
else
{
if (value < 16 || value > 24)
{
as_bad (_("Memory mapped register \"%s\" out of range"),
operand->buf);
return 0;
}
if (type == OP_MMRX)
insn->opcode[0].word |= (value - 16) << 4;
else
insn->opcode[0].word |= (value - 16);
}
return 1;
}
case OP_B:
case OP_A:
return 1;
case OP_SHFT:
return encode_integer (insn, operand, ext + insn->is_lkaddr,
0, 15, 0xF);
case OP_SHIFT:
return encode_integer (insn, operand, ext + insn->is_lkaddr,
-16, 15, 0x1F);
case OP_lk:
return encode_integer (insn, operand, 1 + insn->is_lkaddr,
-32768, 32767, 0xFFFF);
case OP_CC:
return encode_condition (insn, operand);
case OP_CC2:
return encode_cc2 (insn, operand);
case OP_CC3:
return encode_cc3 (insn, operand);
case OP_BITC:
return encode_integer (insn, operand, 0, 0, 15, 0xF);
case OP_k8:
return encode_integer (insn, operand, 0, -128, 127, 0xFF);
case OP_123:
{
int value = operand->exp.X_add_number;
int code;
if (value < 1 || value > 3)
{
as_bad (_("Invalid operand (use 1, 2, or 3)"));
return 0;
}
code = value == 1 ? 0 : value == 2 ? 0x2 : 0x1;
insn->opcode[0].word |= (code << 8);
return 1;
}
case OP_031:
return encode_integer (insn, operand, 0, 0, 31, 0x1F);
case OP_k8u:
return encode_integer (insn, operand, 0, 0, 255, 0xFF);
case OP_lku:
return encode_integer (insn, operand, 1 + insn->is_lkaddr,
0, 65535, 0xFFFF);
case OP_SBIT:
{
symbol *sbit = (symbol *) hash_find (sbit_hash, operand->buf);
int value = is_absolute (operand) ?
operand->exp.X_add_number : (sbit ? sbit->value : -1);
int reg = 0;
if (insn->opcount == 1)
{
if (!sbit)
{
as_bad (_("A status register or status bit name is required"));
return 0;
}
if (sbit > (symbol *) hash_find (sbit_hash, "ovb"))
reg = 1;
}
if (value == -1)
{
as_bad (_("Unrecognized status bit \"%s\""), operand->buf);
return 0;
}
insn->opcode[0].word |= value;
insn->opcode[0].word |= (reg << 9);
return 1;
}
case OP_N:
if (strcasecmp (operand->buf, "st0") == 0
|| strcasecmp (operand->buf, "st1") == 0)
{
insn->opcode[0].word |=
((unsigned short) (operand->buf[2] - '0')) << 9;
return 1;
}
else if (operand->exp.X_op == O_constant
&& (operand->exp.X_add_number == 0
|| operand->exp.X_add_number == 1))
{
insn->opcode[0].word |=
((unsigned short) (operand->exp.X_add_number)) << 9;
return 1;
}
as_bad (_("Invalid status register \"%s\""), operand->buf);
return 0;
case OP_k5:
return encode_integer (insn, operand, 0, -16, 15, 0x1F);
case OP_k3:
return encode_integer (insn, operand, 0, 0, 7, 0x7);
case OP_k9:
return encode_integer (insn, operand, 0, 0, 0x1FF, 0x1FF);
case OP_12:
if (operand->exp.X_add_number != 1
&& operand->exp.X_add_number != 2)
{
as_bad (_("Operand \"%s\" out of range (use 1 or 2)"), operand->buf);
return 0;
}
insn->opcode[0].word |= (operand->exp.X_add_number - 1) << 9;
return 1;
case OP_16:
case OP_T:
case OP_TS:
case OP_ASM:
case OP_TRN:
case OP_DP:
case OP_ARP:
return 1;
default:
return 0;
}
return 1;
}
static void
emit_insn (insn)
tic54x_insn *insn;
{
int i;
flagword oldflags = bfd_get_section_flags (stdoutput, now_seg);
flagword flags = oldflags | SEC_CODE;
if (! bfd_set_section_flags (stdoutput, now_seg, flags))
as_warn (_("error setting flags for \"%s\": %s"),
bfd_section_name (stdoutput, now_seg),
bfd_errmsg (bfd_get_error ()));
for (i = 0; i < insn->words; i++)
{
int size = (insn->opcode[i].unresolved
&& insn->opcode[i].r_type == BFD_RELOC_TIC54X_23) ? 4 : 2;
char *p = frag_more (size);
if (size == 2)
md_number_to_chars (p, (valueT) insn->opcode[i].word, 2);
else
md_number_to_chars (p, (valueT) insn->opcode[i].word << 16, 4);
if (insn->opcode[i].unresolved)
fix_new_exp (frag_now, p - frag_now->fr_literal,
insn->opcode[i].r_nchars, &insn->opcode[i].addr_expr,
FALSE, insn->opcode[i].r_type);
}
}
static int
build_insn (insn)
tic54x_insn *insn;
{
int i;
if (!(insn->tm->flags & FL_PAR))
{
for (i = 0; i < insn->opcount; i++)
{
if ((OPTYPE (insn->operands[i].type) == OP_Smem
|| OPTYPE (insn->operands[i].type) == OP_Lmem
|| OPTYPE (insn->operands[i].type) == OP_Sind)
&& strchr (insn->operands[i].buf, '(')
&& strncasecmp (insn->operands[i].buf, "*sp (", 4) != 0)
{
insn->is_lkaddr = 1;
insn->lkoperand = i;
break;
}
}
}
insn->words = insn->tm->words + insn->is_lkaddr;
insn->opcode[0].word = insn->tm->opcode;
if (insn->tm->flags & FL_EXT)
insn->opcode[1 + insn->is_lkaddr].word = insn->tm->opcode2;
for (i = 0; i < insn->opcount; i++)
{
enum optype type = insn->operands[i].type;
if (!encode_operand (insn, type, &insn->operands[i]))
return 0;
}
if (insn->tm->flags & FL_PAR)
for (i = 0; i < insn->paropcount; i++)
{
enum optype partype = insn->paroperands[i].type;
if (!encode_operand (insn, partype, &insn->paroperands[i]))
return 0;
}
emit_insn (insn);
return insn->words;
}
static int
optimize_insn (insn)
tic54x_insn *insn;
{
#define is_zero(op) ((op).exp.X_op == O_constant && (op).exp.X_add_number == 0)
if (strcasecmp (insn->tm->name, "add") == 0)
{
if (insn->opcount > 1
&& is_accumulator (&insn->operands[insn->opcount - 2])
&& is_accumulator (&insn->operands[insn->opcount - 1])
&& strcasecmp (insn->operands[insn->opcount - 2].buf,
insn->operands[insn->opcount - 1].buf) == 0)
{
--insn->opcount;
insn->using_default_dst = 1;
return 1;
}
if ((OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
&& OPTYPE (insn->tm->operand_types[1]) == OP_SHFT
&& is_zero (insn->operands[1]))
|| (OPTYPE (insn->tm->operand_types[0]) == OP_Smem
&& OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
&& is_type (&insn->operands[1], OP_SHIFT)
&& is_zero (insn->operands[1]) && insn->opcount == 3))
{
insn->operands[1] = insn->operands[2];
insn->opcount = 2;
return 1;
}
}
else if (strcasecmp (insn->tm->name, "ld") == 0)
{
if (insn->opcount == 3 && insn->operands[0].type != OP_SRC)
{
if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
|| OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
&& is_zero (insn->operands[1])
&& (OPTYPE (insn->tm->operand_types[0]) != OP_lk
|| (insn->operands[0].exp.X_op == O_constant
&& insn->operands[0].exp.X_add_number <= 255
&& insn->operands[0].exp.X_add_number >= 0)))
{
insn->operands[1] = insn->operands[2];
insn->opcount = 2;
return 1;
}
}
}
else if (strcasecmp (insn->tm->name, "sth") == 0
|| strcasecmp (insn->tm->name, "stl") == 0)
{
if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
|| OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
&& is_zero (insn->operands[1]))
{
insn->operands[1] = insn->operands[2];
insn->opcount = 2;
return 1;
}
}
else if (strcasecmp (insn->tm->name, "sub") == 0)
{
if (insn->opcount > 1
&& is_accumulator (&insn->operands[insn->opcount - 2])
&& is_accumulator (&insn->operands[insn->opcount - 1])
&& strcasecmp (insn->operands[insn->opcount - 2].buf,
insn->operands[insn->opcount - 1].buf) == 0)
{
--insn->opcount;
insn->using_default_dst = 1;
return 1;
}
if ( ((OPTYPE (insn->tm->operand_types[0]) == OP_Smem
&& OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT)
|| (OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
&& OPTYPE (insn->tm->operand_types[1]) == OP_SHFT))
&& is_zero (insn->operands[1])
&& insn->opcount == 3)
{
insn->operands[1] = insn->operands[2];
insn->opcount = 2;
return 1;
}
}
return 0;
}
static int
tic54x_parse_insn (insn, line)
tic54x_insn *insn;
char *line;
{
insn->tm = (template *) hash_find (op_hash, insn->mnemonic);
if (!insn->tm)
{
as_bad (_("Unrecognized instruction \"%s\""), insn->mnemonic);
return 0;
}
insn->opcount = get_operands (insn->operands, line);
if (insn->opcount < 0)
return 0;
while (insn->tm->name && strcasecmp (insn->tm->name, insn->mnemonic) == 0)
{
if (insn->opcount >= insn->tm->minops
&& insn->opcount <= insn->tm->maxops
&& operands_match (insn, &insn->operands[0], insn->opcount,
insn->tm->operand_types,
insn->tm->minops, insn->tm->maxops))
{
if (optimize_insn (insn))
{
insn->tm = (template *) hash_find (op_hash,
insn->mnemonic);
continue;
}
return 1;
}
++(insn->tm);
}
as_bad (_("Unrecognized operand list '%s' for instruction '%s'"),
line, insn->mnemonic);
return 0;
}
static int parallel_on_next_line_hint = 0;
static int
next_line_shows_parallel (next_line)
char *next_line;
{
while (ISSPACE (*next_line))
++next_line;
return (next_line[0] == PARALLEL_SEPARATOR
&& next_line[1] == PARALLEL_SEPARATOR);
}
static int
tic54x_parse_parallel_insn_firstline (insn, line)
tic54x_insn *insn;
char *line;
{
insn->tm = (template *) hash_find (parop_hash, insn->mnemonic);
if (!insn->tm)
{
as_bad (_("Unrecognized parallel instruction \"%s\""),
insn->mnemonic);
return 0;
}
while (insn->tm->name && strcasecmp (insn->tm->name,
insn->mnemonic) == 0)
{
insn->opcount = get_operands (insn->operands, line);
if (insn->opcount < 0)
return 0;
if (insn->opcount == 2
&& operands_match (insn, &insn->operands[0], insn->opcount,
insn->tm->operand_types, 2, 2))
{
return 1;
}
++(insn->tm);
}
return 0;
}
static int
tic54x_parse_parallel_insn_lastline (insn, line)
tic54x_insn *insn;
char *line;
{
int valid_mnemonic = 0;
insn->paropcount = get_operands (insn->paroperands, line);
while (insn->tm->name && strcasecmp (insn->tm->name,
insn->mnemonic) == 0)
{
if (strcasecmp (insn->tm->parname, insn->parmnemonic) == 0)
{
valid_mnemonic = 1;
if (insn->paropcount >= insn->tm->minops
&& insn->paropcount <= insn->tm->maxops
&& operands_match (insn, insn->paroperands,
insn->paropcount,
insn->tm->paroperand_types,
insn->tm->minops, insn->tm->maxops))
return 1;
}
++(insn->tm);
}
if (valid_mnemonic)
as_bad (_("Invalid operand (s) for parallel instruction \"%s\""),
insn->parmnemonic);
else
as_bad (_("Unrecognized parallel instruction combination \"%s || %s\""),
insn->mnemonic, insn->parmnemonic);
return 0;
}
static char *
subsym_get_arg (line, terminators, str, nosub)
char *line;
char *terminators;
char **str;
int nosub;
{
char *ptr = line;
char *endp;
int is_string = *line == '"';
int is_char = ISDIGIT (*line);
if (is_char)
{
while (ISDIGIT (*ptr))
++ptr;
endp = ptr;
*str = xmalloc (ptr - line + 1);
strncpy (*str, line, ptr - line);
(*str)[ptr - line] = 0;
}
else if (is_string)
{
char *savedp = input_line_pointer;
int len;
input_line_pointer = ptr;
*str = demand_copy_C_string (&len);
endp = input_line_pointer;
input_line_pointer = savedp;
if (!nosub && **str == ':')
*str = subsym_substitute (*str, 1);
}
else
{
char *term = terminators;
char *value = NULL;
while (*ptr && *ptr != *term)
{
if (!*term)
{
term = terminators;
++ptr;
}
else
++term;
}
endp = ptr;
*str = xmalloc (ptr - line + 1);
strncpy (*str, line, ptr - line);
(*str)[ptr - line] = 0;
if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL)
*str = value;
}
return endp;
}
static void
subsym_create_or_replace (name, value)
char *name;
char *value;
{
int i;
for (i = macro_level; i > 0; i--)
{
if (hash_find (subsym_hash[i], name))
{
hash_replace (subsym_hash[i], name, value);
return;
}
}
if (hash_find (subsym_hash[0], name))
hash_replace (subsym_hash[0], name, value);
else
hash_insert (subsym_hash[0], name, value);
}
static char *
subsym_lookup (name, nest_level)
char *name;
int nest_level;
{
char *value = hash_find (subsym_hash[nest_level], name);
if (value || nest_level == 0)
return value;
return subsym_lookup (name, nest_level - 1);
}
static char *
subsym_substitute (line, forced)
char * line;
int forced;
{
char *replacement;
char *head;
char *ptr;
int changed = 0;
int eval_line = 0;
int eval_symbol = 0;
char *eval_end = NULL;
int recurse = 1;
int line_conditional = 0;
char *tmp;
replacement = xmalloc (strlen (line) + 1);
strcpy (replacement, line);
ptr = head = replacement;
if (strstr (line, ".if")
|| strstr (line, ".elseif")
|| strstr (line, ".break"))
line_conditional = 1;
if (strstr (line, ".eval") || strstr (line, ".asg"))
eval_line = 1;
if (strstr (line, ".macro"))
return line;
while (!is_end_of_line[(int) *ptr])
{
int current_char = *ptr;
if (eval_line)
eval_end = strrchr (ptr, ',');
if (current_char == '"' && ptr[1] == '"' && ptr[2] == '"')
{
ptr[1] = '\\';
tmp = strstr (ptr + 2, "\"\"\"");
if (tmp)
tmp[0] = '\\';
changed = 1;
}
if (line_conditional && current_char == '=')
{
if (ptr[1] == '=')
{
ptr += 2;
continue;
}
*ptr++ = '\0';
tmp = xmalloc (strlen (head) + 2 + strlen (ptr) + 1);
sprintf (tmp, "%s==%s", head, ptr);
ptr = tmp + strlen (head) + 2;
free (replacement);
head = replacement = tmp;
changed = 1;
}
if (eval_line && ptr >= eval_end)
eval_symbol = 1;
if ((forced && current_char == ':')
|| (!forced && is_name_beginner (current_char)))
{
char *name;
char *savedp = input_line_pointer;
int c;
char *value = NULL;
char *tail;
if (forced)
++ptr;
name = input_line_pointer = ptr;
c = get_symbol_end ();
if (c == '?')
{
*input_line_pointer++ = c;
c = *input_line_pointer;
*input_line_pointer = '\0';
}
if (hash_find (subsym_recurse_hash, name) == NULL)
value = subsym_lookup (name, macro_level);
else
as_warn (_("%s symbol recursion stopped at "
"second appearance of '%s'"),
forced ? "Forced substitution" : "Substitution", name);
ptr = tail = input_line_pointer;
input_line_pointer = savedp;
if ((*name == '$' && ISDIGIT (name[1]) && name[2] == '\0')
|| name[strlen (name) - 1] == '?')
{
value = hash_find (local_label_hash[macro_level], name);
if (value == NULL)
{
char digit[11];
char *namecopy = strcpy (xmalloc (strlen (name) + 1), name);
value = strcpy (xmalloc (strlen (name) + sizeof (digit) + 1),
name);
if (*value != '$')
value[strlen (value) - 1] = '\0';
sprintf (digit, ".%d", local_label_id++);
strcat (value, digit);
hash_insert (local_label_hash[macro_level], namecopy, value);
}
ptr = tail;
}
else if (value != NULL && *name == '$')
{
subsym_proc_entry *entry = (subsym_proc_entry *) value;
math_proc_entry *math_entry = hash_find (math_hash, name);
char *arg1, *arg2 = NULL;
*ptr = c;
if (entry == NULL)
{
as_bad (_("Unrecognized substitution symbol function"));
break;
}
else if (*ptr != '(')
{
as_bad (_("Missing '(' after substitution symbol function"));
break;
}
++ptr;
if (math_entry != NULL)
{
float arg1, arg2 = 0;
volatile float fresult;
arg1 = (float) strtod (ptr, &ptr);
if (math_entry->nargs == 2)
{
if (*ptr++ != ',')
{
as_bad (_("Expecting second argument"));
break;
}
arg2 = (float) strtod (ptr, &ptr);
}
fresult = (*math_entry->proc) (arg1, arg2);
value = xmalloc (128);
if (math_entry->int_return)
sprintf (value, "%d", (int) fresult);
else
sprintf (value, "%f", fresult);
if (*ptr++ != ')')
{
as_bad (_("Extra junk in function call, expecting ')'"));
break;
}
recurse = 0;
}
else
{
int val;
int arg_type[2] = { *ptr == '"' , 0 };
int ismember = !strcmp (entry->name, "$ismember");
ptr = subsym_get_arg (ptr, ",)", &arg1, ismember);
if (!arg1)
break;
if (entry->nargs == 2)
{
if (*ptr++ != ',')
{
as_bad (_("Function expects two arguments"));
break;
}
arg_type[1] = (ISDIGIT (*ptr)) ? 2 : (*ptr == '"');
ptr = subsym_get_arg (ptr, ")", &arg2, ismember);
}
if ((!strcmp (entry->name, "$firstch")
|| !strcmp (entry->name, "$lastch"))
&& arg_type[1] != 2)
{
as_bad (_("Expecting character constant argument"));
break;
}
if (ismember
&& (arg_type[0] != 0 || arg_type[1] != 0))
{
as_bad (_("Both arguments must be substitution symbols"));
break;
}
if (*ptr++ != ')')
{
as_bad (_("Extra junk in function call, expecting ')'"));
break;
}
val = (*entry->proc) (arg1, arg2);
value = xmalloc (64);
sprintf (value, "%d", val);
}
tail = ptr;
c = *tail;
}
if (value != NULL && !eval_symbol)
{
if (recurse)
{
hash_insert (subsym_recurse_hash, name, name);
value = subsym_substitute (value, macro_level > 0);
hash_delete (subsym_recurse_hash, name);
}
*name = 0;
if (forced)
{
if (c == '(')
{
unsigned beg, len = 1;
char *newval = strcpy (xmalloc (strlen (value) + 1),
value);
savedp = input_line_pointer;
input_line_pointer = tail + 1;
beg = get_absolute_expression ();
if (beg < 1)
{
as_bad (_("Invalid subscript (use 1 to %d)"),
strlen (value));
break;
}
if (*input_line_pointer == ',')
{
++input_line_pointer;
len = get_absolute_expression ();
if (beg + len > strlen (value))
{
as_bad (_("Invalid length (use 0 to %d"),
strlen (value) - beg);
break;
}
}
newval += beg - 1;
newval[len] = 0;
tail = input_line_pointer;
if (*tail++ != ')')
{
as_bad (_("Missing ')' in subscripted substitution "
"symbol expression"));
break;
}
c = *tail;
input_line_pointer = savedp;
value = newval;
}
name[-1] = 0;
}
tmp = xmalloc (strlen (head) + strlen (value) +
strlen (tail + 1) + 2);
strcpy (tmp, head);
strcat (tmp, value);
if (forced)
{
if (c != ':')
{
as_bad (_("Missing forced substitution terminator ':'"));
break;
}
++tail;
}
else
*tail = c;
strcat (tmp, tail);
ptr = tmp + strlen (head) + strlen (value);
free (replacement);
head = replacement = tmp;
changed = 1;
}
else
*ptr = c;
}
else
{
++ptr;
}
}
if (changed)
return replacement;
else
return line;
}
void
tic54x_start_line_hook ()
{
char *line, *endp;
char *replacement = NULL;
endp = input_line_pointer;
while (!is_end_of_line[(int) *endp++])
;
line = xmalloc (endp - input_line_pointer + 1);
strncpy (line, input_line_pointer, endp - input_line_pointer + 1);
line[endp - input_line_pointer] = 0;
parallel_on_next_line_hint = next_line_shows_parallel (endp + 1);
if (macro_level > 0)
replacement = subsym_substitute (line, 1);
else
replacement = line;
replacement = subsym_substitute (replacement, 0);
if (replacement != line)
{
char *tmp = replacement;
char *comment = strchr (replacement, ';');
char endc = replacement[strlen (replacement) - 1];
if (comment != NULL)
{
comment[0] = endc;
comment[1] = 0;
--comment;
}
else
comment = replacement + strlen (replacement) - 1;
while (ISSPACE (*comment))
{
comment[0] = endc;
comment[1] = 0;
--comment;
}
while (ISSPACE (tmp[0]) && ISSPACE (tmp[1]))
++tmp;
input_line_pointer = endp;
input_scrub_insert_line (tmp);
free (replacement);
free (line);
substitution_line = 1;
}
else
{
free (line);
substitution_line = 0;
}
}
void
md_assemble (line)
char *line;
{
static int repeat_slot = 0;
static int delay_slots = 0;
static int is_parallel = 0;
static tic54x_insn insn;
char *lptr;
char *savedp = input_line_pointer;
int c;
input_line_pointer = line;
c = get_symbol_end ();
if (cpu == VNONE)
cpu = V542;
if (address_mode_needs_set)
{
set_address_mode (amode);
address_mode_needs_set = 0;
}
if (cpu_needs_set)
{
set_cpu (cpu);
cpu_needs_set = 0;
}
assembly_begun = 1;
if (is_parallel)
{
is_parallel = 0;
strcpy (insn.parmnemonic, line);
lptr = input_line_pointer;
*lptr = c;
input_line_pointer = savedp;
if (tic54x_parse_parallel_insn_lastline (&insn, lptr))
{
int words = build_insn (&insn);
if (delay_slots != 0)
{
if (words > delay_slots)
{
as_bad (_("Instruction does not fit in available delay "
"slots (%d-word insn, %d slots left)"),
words, delay_slots);
delay_slots = 0;
return;
}
delay_slots -= words;
}
}
return;
}
memset (&insn, 0, sizeof (insn));
strcpy (insn.mnemonic, line);
lptr = input_line_pointer;
*lptr = c;
input_line_pointer = savedp;
if (strstr (line, "||") != NULL || parallel_on_next_line_hint)
{
char *tmp = strstr (line, "||");
if (tmp != NULL)
*tmp = '\0';
if (tic54x_parse_parallel_insn_firstline (&insn, lptr))
{
is_parallel = 1;
if (tmp != NULL)
{
while (ISSPACE (tmp[2]))
++tmp;
md_assemble (tmp + 2);
}
}
else
{
as_bad (_("Unrecognized parallel instruction '%s'"), line);
}
return;
}
if (tic54x_parse_insn (&insn, lptr))
{
int words;
if ((insn.tm->flags & FL_LP)
&& cpu != V545LP && cpu != V546LP)
{
as_bad (_("Instruction '%s' requires an LP cpu version"),
insn.tm->name);
return;
}
if ((insn.tm->flags & FL_FAR)
&& amode != far_mode)
{
as_bad (_("Instruction '%s' requires far mode addressing"),
insn.tm->name);
return;
}
words = build_insn (&insn);
if (delay_slots)
{
if (words > delay_slots)
{
as_warn (_("Instruction does not fit in available delay "
"slots (%d-word insn, %d slots left). "
"Resulting behavior is undefined."),
words, delay_slots);
delay_slots = 0;
return;
}
if (insn.tm->flags & FL_BMASK)
{
as_warn (_("Instructions which cause PC discontinuity are not "
"allowed in a delay slot. "
"Resulting behavior is undefined."));
}
delay_slots -= words;
}
if (repeat_slot)
{
if (insn.tm->flags & FL_NR)
as_warn (_("'%s' is not repeatable. "
"Resulting behavior is undefined."),
insn.tm->name);
else if (insn.is_lkaddr)
as_warn (_("Instructions using long offset modifiers or absolute "
"addresses are not repeatable. "
"Resulting behavior is undefined."));
repeat_slot = 0;
}
if (insn.tm->flags & B_REPEAT)
{
repeat_slot = 1;
}
if (insn.tm->flags & FL_DELAY)
{
delay_slots = 2;
}
}
}
void
tic54x_adjust_symtab ()
{
if (symbol_rootP == NULL
|| S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
{
char *filename;
unsigned lineno;
as_where (&filename, &lineno);
c_dot_file_symbol (filename, 0);
}
}
int
tic54x_unrecognized_line (int c)
{
return c == PARALLEL_SEPARATOR;
}
void
tic54x_define_label (sym)
symbolS *sym;
{
last_label_seen = sym;
}
symbolS *
tic54x_undefined_symbol (name)
char *name;
{
symbol *sym;
if ((sym = (symbol *) hash_find (cc_hash, name)) != NULL ||
(sym = (symbol *) hash_find (cc2_hash, name)) != NULL ||
(sym = (symbol *) hash_find (cc3_hash, name)) != NULL ||
(sym = (symbol *) hash_find (misc_symbol_hash, name)) != NULL ||
(sym = (symbol *) hash_find (sbit_hash, name)) != NULL)
{
return symbol_new (name, reg_section,
(valueT) sym->value,
&zero_address_frag);
}
if ((sym = (symbol *) hash_find (reg_hash, name)) != NULL ||
(sym = (symbol *) hash_find (mmreg_hash, name)) != NULL ||
!strcasecmp (name, "a") || !strcasecmp (name, "b"))
{
return symbol_new (name, reg_section,
(valueT) sym ? sym->value : 0,
&zero_address_frag);
}
return NULL;
}
int
tic54x_parse_name (name, exp)
char *name ATTRIBUTE_UNUSED;
expressionS *exp ATTRIBUTE_UNUSED;
{
return 0;
}
char *
md_atof (type, literalP, sizeP)
int type;
char *literalP;
int *sizeP;
{
#define MAX_LITTLENUMS 2
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *word;
int prec = 2;
char *t = atof_ieee (input_line_pointer, type, words);
if (t)
input_line_pointer = t;
*sizeP = 4;
for (word = words; prec--;)
{
md_number_to_chars (literalP, (long) (*word++), sizeof (LITTLENUM_TYPE));
literalP += sizeof (LITTLENUM_TYPE);
}
return 0;
}
arelent *
tc_gen_reloc (section, fixP)
asection *section;
fixS *fixP;
{
arelent *rel;
bfd_reloc_code_real_type code = fixP->fx_r_type;
asymbol *sym = symbol_get_bfdsym (fixP->fx_addsy);
rel = (arelent *) xmalloc (sizeof (arelent));
rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*rel->sym_ptr_ptr = sym;
rel->address = fixP->fx_frag->fr_address + fixP->fx_where;
rel->address /= OCTETS_PER_BYTE;
rel->howto = bfd_reloc_type_lookup (stdoutput, code);
if (!strcmp (sym->name, section->name))
rel->howto += HOWTO_BANK;
if (!rel->howto)
{
const char *name = S_GET_NAME (fixP->fx_addsy);
if (name == NULL)
name = "<unknown>";
as_fatal ("Cannot generate relocation type for symbol %s, code %s",
name, bfd_get_reloc_code_name (code));
return NULL;
}
return rel;
}
void
tic54x_cons_fix_new (frag, where, octets, exp)
fragS *frag;
int where;
int octets;
expressionS *exp;
{
bfd_reloc_code_real_type r;
switch (octets)
{
default:
as_bad (_("Unsupported relocation size %d"), octets);
r = BFD_RELOC_TIC54X_16_OF_23;
break;
case 2:
r = BFD_RELOC_TIC54X_16_OF_23;
break;
case 4:
if (emitting_long)
r = BFD_RELOC_TIC54X_23;
else
r = BFD_RELOC_32;
break;
}
fix_new_exp (frag, where, octets, exp, 0, r);
}
void
md_apply_fix3 (fixP, valP, seg)
fixS *fixP;
valueT * valP;
segT seg ATTRIBUTE_UNUSED;
{
char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
valueT val = * valP;
switch (fixP->fx_r_type)
{
default:
as_fatal ("Bad relocation type: 0x%02x", fixP->fx_r_type);
return;
case BFD_RELOC_TIC54X_MS7_OF_23:
val = (val >> 16) & 0x7F;
case BFD_RELOC_TIC54X_16_OF_23:
case BFD_RELOC_16:
bfd_put_16 (stdoutput, val, buf);
*valP = val & 0xFFFF;
break;
case BFD_RELOC_TIC54X_PARTLS7:
bfd_put_16 (stdoutput,
(bfd_get_16 (stdoutput, buf) & 0xFF80) | (val & 0x7F),
buf);
*valP = val & 0x7F;
break;
case BFD_RELOC_TIC54X_PARTMS9:
bfd_put_16 (stdoutput,
(bfd_get_16 (stdoutput, buf) & 0xFE00) | (val >> 7),
buf);
break;
case BFD_RELOC_32:
case BFD_RELOC_TIC54X_23:
bfd_put_32 (stdoutput,
(bfd_get_32 (stdoutput, buf) & 0xFF800000) | val,
buf);
break;
}
if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
fixP->fx_done = 1;
}
valueT
md_section_align (segment, section_size)
segT segment ATTRIBUTE_UNUSED;
valueT section_size;
{
return section_size;
}
long
md_pcrel_from (fixP)
fixS *fixP ATTRIBUTE_UNUSED;
{
return 0;
}
#if defined OBJ_COFF
short
tc_coff_fix2rtype (fixP)
fixS *fixP;
{
return (fixP->fx_r_type);
}
#endif
void
tic54x_number_to_chars (buf, val, n)
char *buf;
valueT val;
int n;
{
if (n != 4)
number_to_chars_littleendian (buf, val, n);
else
{
number_to_chars_littleendian (buf , val >> 16 , 2);
number_to_chars_littleendian (buf + 2, val & 0xFFFF, 2);
}
}
int
tic54x_estimate_size_before_relax (frag, seg)
fragS *frag ATTRIBUTE_UNUSED;
segT seg ATTRIBUTE_UNUSED;
{
return 0;
}
int
tic54x_relax_frag (frag, stretch)
fragS *frag;
long stretch ATTRIBUTE_UNUSED;
{
symbolS *sym = frag->fr_symbol;
int growth = 0;
int i;
if (sym != NULL)
{
struct bit_info *bi = (struct bit_info *) frag->fr_opcode;
int bit_offset = frag_bit_offset (frag_prev (frag, bi->seg), bi->seg);
int size = S_GET_VALUE (sym);
fragS *prev_frag = bit_offset_frag (frag_prev (frag, bi->seg), bi->seg);
int available = 16 - bit_offset;
if (symbol_get_frag (sym) != &zero_address_frag
|| S_IS_COMMON (sym)
|| !S_IS_DEFINED (sym))
as_bad_where (frag->fr_file, frag->fr_line,
_("non-absolute value used with .space/.bes"));
if (size < 0)
{
as_warn (_("negative value ignored in %s"),
bi->type == TYPE_SPACE ? ".space" :
bi->type == TYPE_BES ? ".bes" : ".field");
growth = 0;
frag->tc_frag_data = frag->fr_fix = 0;
return 0;
}
if (bi->type == TYPE_FIELD)
{
if (bit_offset != 0 && available >= size)
{
char *p = prev_frag->fr_literal;
valueT value = bi->value;
value <<= available - size;
value |= ((unsigned short) p[1] << 8) | p[0];
md_number_to_chars (p, value, 2);
if ((prev_frag->tc_frag_data += size) == 16)
prev_frag->tc_frag_data = 0;
if (bi->sym)
symbol_set_frag (bi->sym, prev_frag);
growth = -frag->fr_fix;
frag->fr_fix = 0;
frag->tc_frag_data = 0;
}
else
{
char *p = frag->fr_literal;
valueT value = bi->value << (16 - size);
md_number_to_chars (p, value, 2);
if ((frag->tc_frag_data = size) == 16)
frag->tc_frag_data = 0;
growth = 0;
}
}
else
{
if (bit_offset != 0 && bit_offset < 16)
{
if (available >= size)
{
if ((prev_frag->tc_frag_data += size) == 16)
prev_frag->tc_frag_data = 0;
if (bi->sym)
symbol_set_frag (bi->sym, prev_frag);
growth = -frag->fr_fix;
frag->fr_fix = 0;
frag->tc_frag_data = 0;
goto getout;
}
if (bi->type == TYPE_SPACE && bi->sym)
symbol_set_frag (bi->sym, prev_frag);
size -= available;
}
growth = (size + 15) / 16 * OCTETS_PER_BYTE - frag->fr_fix;
for (i = 0; i < growth; i++)
frag->fr_literal[i] = 0;
frag->fr_fix = growth;
frag->tc_frag_data = size % 16;
if (bi->type == TYPE_BES && bi->sym)
S_SET_VALUE (bi->sym, frag->fr_fix / OCTETS_PER_BYTE - 1);
}
getout:
frag->fr_symbol = 0;
frag->fr_opcode = 0;
free ((void *) bi);
}
return growth;
}
void
tic54x_convert_frag (abfd, seg, frag)
bfd *abfd ATTRIBUTE_UNUSED;
segT seg ATTRIBUTE_UNUSED;
fragS *frag;
{
frag->fr_offset = (frag->fr_next->fr_address
- frag->fr_address
- frag->fr_fix) / frag->fr_var;
if (frag->fr_offset < 0)
{
as_bad_where (frag->fr_file, frag->fr_line,
_("attempt to .space/.bes backwards? (%ld)"),
(long) frag->fr_offset);
}
frag->fr_type = rs_space;
}
int
tic54x_start_label (c, rest)
int c;
char *rest;
{
if (current_stag != NULL)
return 0;
if (c != ':')
{
char *label = rest;
while (!is_end_of_line[(int) label[-1]])
--label;
if (*label == '.')
{
as_bad (_("Invalid label '%s'"), label);
return 0;
}
}
if (is_end_of_line[(int) c])
return 1;
if (ISSPACE (c))
while (ISSPACE (c = *++rest))
;
if (c == '.')
{
return (strncasecmp (rest, ".tag", 4) != 0 || !ISSPACE (rest[4]))
&& (strncasecmp (rest, ".struct", 7) != 0 || !ISSPACE (rest[7]))
&& (strncasecmp (rest, ".union", 6) != 0 || !ISSPACE (rest[6]))
&& (strncasecmp (rest, ".macro", 6) != 0 || !ISSPACE (rest[6]))
&& (strncasecmp (rest, ".set", 4) != 0 || !ISSPACE (rest[4]))
&& (strncasecmp (rest, ".equ", 4) != 0 || !ISSPACE (rest[4]));
}
return 1;
}