aboutsummaryrefslogtreecommitdiff
path: root/gas/config
diff options
context:
space:
mode:
authorMartin Hunt <hunt@redhat.com>1996-07-22 18:55:27 +0000
committerMartin Hunt <hunt@redhat.com>1996-07-22 18:55:27 +0000
commit0ef325594af012f7bc3b56143fc1f26caf66069a (patch)
treeaf35a6e8aba6c77f10d9825c784d58f2ee8d2e71 /gas/config
parentd82a4ac0aa296fbfaca94141c7244c1e73881676 (diff)
downloadfsf-binutils-gdb-0ef325594af012f7bc3b56143fc1f26caf66069a.zip
fsf-binutils-gdb-0ef325594af012f7bc3b56143fc1f26caf66069a.tar.gz
fsf-binutils-gdb-0ef325594af012f7bc3b56143fc1f26caf66069a.tar.bz2
start-sanitize-d10v
Mon Jul 22 11:32:36 1996 Martin M. Hunt <hunt@pizza.cygnus.com> * config/tc-d10v.c: Many changes to get relocs working. (register_name): No longer creates a symbol for register names. (pre_defined_registers): moved to opcodes/d10v-opc.c. (d10v_insert_operand): Now works correctly for either container. * config/tc-d10v.h (d10v_cleanup): Declare. end-sanitize-d10v
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-d10v.c324
-rw-r--r--gas/config/tc-d10v.h8
2 files changed, 176 insertions, 156 deletions
diff --git a/gas/config/tc-d10v.c b/gas/config/tc-d10v.c
index ccddaf4..c1a9465 100644
--- a/gas/config/tc-d10v.c
+++ b/gas/config/tc-d10v.c
@@ -33,29 +33,40 @@ const char *md_shortopts = "";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "dD";
+
+/* fixups */
+#define MAX_INSN_FIXUPS (5)
+struct d10v_fixup
+{
+ expressionS exp;
+ bfd_reloc_code_real_type reloc;
+};
+
+typedef struct _fixups
+{
+ int fc;
+ struct d10v_fixup fix[MAX_INSN_FIXUPS];
+ struct _fixups *next;
+} Fixups;
+
+static Fixups FixUps[2];
+static Fixups *fixups;
+
/* local functions */
static int reg_name_search PARAMS ((char *name));
-static void register_name PARAMS ((expressionS *expressionP));
+static int register_name PARAMS ((expressionS *expressionP));
static int postfix PARAMS ((char *p));
static bfd_reloc_code_real_type get_reloc PARAMS ((struct d10v_operand *op));
static int get_operands PARAMS ((expressionS exp[]));
static unsigned long build_insn PARAMS ((struct d10v_opcode *opcode, expressionS *opers));
-static void write_long PARAMS ((struct d10v_opcode *opcode, unsigned long insn));
-static void write_1_short PARAMS ((struct d10v_opcode *opcode, unsigned long insn));
+static void write_long PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx));
+static void write_1_short PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx));
static int write_2_short PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1,
- struct d10v_opcode *opcode2, unsigned long insn2, int exec_type));
+ struct d10v_opcode *opcode2, unsigned long insn2, int exec_type, Fixups *fx));
static unsigned long do_assemble PARAMS ((char *str, struct d10v_opcode **opcode));
+static unsigned long d10v_insert_operand PARAMS (( unsigned long insn, int op_type,
+ offsetT value, int left));
-/* fixups */
-#define MAX_INSN_FIXUPS (5)
-struct d10v_fixup
-{
- expressionS exp;
- int opindex;
- bfd_reloc_code_real_type reloc;
-};
-struct d10v_fixup fixups[MAX_INSN_FIXUPS];
-static int fc;
struct option md_longopts[] = {
{NULL, no_argument, NULL, 0}
@@ -65,71 +76,12 @@ size_t md_longopts_size = sizeof(md_longopts);
/* The target specific pseudo-ops which we support. */
const pseudo_typeS md_pseudo_table[] =
{
- /*
- { "byte", ppc_byte, 0 },
- { "long", ppc_elf_cons, 4 },
- { "word", ppc_elf_cons, 2 },
- { "short", ppc_elf_cons, 2 },
- { "rdata", ppc_elf_rdata, 0 },
- { "rodata", ppc_elf_rdata, 0 },
- { "lcomm", ppc_elf_lcomm, 0 },
- */
{ NULL, NULL, 0 }
};
/* Opcode hash table. */
static struct hash_control *d10v_hash;
-/* Structure to hold information about predefined registers. */
-struct pd_reg
-{
- char *name;
- int value;
-};
-
-
-/* an expressionS only has one register type, so we fake it */
-/* by setting high bits to indicate type */
-#define REGISTER_MASK 0xFF
-
-/* The table is sorted. Suitable for searching by a binary search. */
-static const struct pd_reg pre_defined_registers[] =
-{
- { "a0", OPERAND_ACC+0 },
- { "a1", OPERAND_ACC+1 },
- { "bpc", OPERAND_CONTROL+3 },
- { "bpsw", OPERAND_CONTROL+1 },
- { "c", OPERAND_FLAG+3 },
- { "f0", OPERAND_FLAG+0 },
- { "f1", OPERAND_FLAG+1 },
- { "iba", OPERAND_CONTROL+14 },
- { "mod_e", OPERAND_CONTROL+11 },
- { "mod_s", OPERAND_CONTROL+10 },
- { "pc", OPERAND_CONTROL+2 },
- { "psw", OPERAND_CONTROL+0 },
- { "r0", 0 },
- { "r1", 1 },
- { "r10", 10 },
- { "r11", 11 },
- { "r12", 12 },
- { "r13", 13 },
- { "r14", 14 },
- { "r15", 15 },
- { "r2", 2 },
- { "r3", 3 },
- { "r4", 4 },
- { "r5", 5 },
- { "r6", 6 },
- { "r7", 7 },
- { "r8", 8 },
- { "r9", 9 },
- { "rpt_c", OPERAND_CONTROL+7 },
- { "rpt_e", OPERAND_CONTROL+9 },
- { "rpt_s", OPERAND_CONTROL+8 },
- { "sp", 15 },
-};
-#define REG_NAME_CNT (sizeof(pre_defined_registers) / sizeof(struct pd_reg))
-
/* reg_name_search does a binary search of the pre_defined_registers
array to see if "name" is a valid regiter name. Returns the register
number from the array on success, or -1 on failure. */
@@ -142,7 +94,7 @@ reg_name_search (name)
int cmp;
low = 0;
- high = REG_NAME_CNT - 1;
+ high = reg_name_cnt() - 1;
do
{
@@ -159,30 +111,37 @@ reg_name_search (name)
return -1;
}
+/* register_name() checks the string at input_line_pointer
+ to see if it is a valid register name */
-/* register_name check to see if an expression is a valid
- register name. If it is, it marks the expression type
- as O_register. */
-
-static void
+static int
register_name (expressionP)
expressionS *expressionP;
{
int reg_number;
- char *name;
+ char c, *p = input_line_pointer;
+
+ while (*p && *p!='\n' && *p!='\r' && *p !=',' && *p!=' ' && *p!=')')
+ p++;
- if (expressionP->X_op == O_symbol)
- {
- name = (char *)S_GET_NAME (expressionP->X_add_symbol);
- reg_number = reg_name_search (name);
+ c = *p;
+ if (c)
+ *p++ = 0;
- /* look to see if it's in the register table */
- if (reg_number >= 0)
- {
- expressionP->X_op = O_register;
- expressionP->X_add_number = reg_number;
- }
+ /* look to see if it's in the register table */
+ reg_number = reg_name_search (input_line_pointer);
+ if (reg_number >= 0)
+ {
+ expressionP->X_op = O_register;
+ /* temporarily store a pointer to the string here */
+ expressionP->X_op_symbol = (struct symbol *)input_line_pointer;
+ expressionP->X_add_number = reg_number;
+ input_line_pointer = p;
+ return 1;
}
+ if (c)
+ *(p-1) = c;
+ return 0;
}
void
@@ -223,7 +182,7 @@ md_convert_frag (abfd, sec, fragP)
asection *sec;
fragS *fragP;
{
- /* printf ("call to md_convert_frag \n"); */
+ printf ("call to md_convert_frag \n");
abort ();
}
@@ -236,6 +195,7 @@ md_section_align (seg, addr)
return ((addr + (1 << align) - 1) & (-1 << align));
}
+
void
md_begin ()
{
@@ -256,6 +216,10 @@ md_begin ()
hash_insert (d10v_hash, opcode->name, (char *) opcode);
}
}
+
+ fixups = &FixUps[0];
+ FixUps[0].next = &FixUps[1];
+ FixUps[1].next = &FixUps[0];
}
@@ -299,8 +263,8 @@ get_reloc (op)
if (op->flags & OPERAND_ADDR)
{
- if (bits == 8)
- return (BFD_RELOC_D10V_10_PCREL_R);
+ if (bits == 8)
+ return (BFD_RELOC_D10V_10_PCREL_R);
else
return (BFD_RELOC_D10V_18_PCREL);
}
@@ -357,10 +321,14 @@ get_operands (exp)
}
input_line_pointer = p;
- /* create an expression */
- expression (&exp[numops]);
+
+
/* check to see if it might be a register name */
- register_name (&exp[numops]);
+ if (!register_name (&exp[numops]))
+ {
+ /* parse as an expression */
+ expression (&exp[numops]);
+ }
if (exp[numops].X_op == O_illegal)
as_bad ("illegal operand");
@@ -388,14 +356,18 @@ get_operands (exp)
}
static unsigned long
-d10v_insert_operand (insn, op_type, value)
+d10v_insert_operand (insn, op_type, value, left)
unsigned long insn;
int op_type;
offsetT value;
+ int left;
{
int shift, bits;
shift = d10v_operands[op_type].shift;
+ if (left)
+ shift += 15;
+
bits = d10v_operands[op_type].bits;
/* truncate to the proper number of bits */
/* FIXME: overflow checking here? */
@@ -443,14 +415,14 @@ build_insn (opcode, opers)
printf("\n");
*/
- if (fc >= MAX_INSN_FIXUPS)
+ if (fixups->fc >= MAX_INSN_FIXUPS)
as_fatal ("too many fixups");
- fixups[fc].exp = opers[i];
+ fixups->fix[fixups->fc].exp = opers[i];
/* put the operand number here for now. We can look up
the reloc type and/or fixup the instruction in md_apply_fix() */
- fixups[fc].reloc = opcode->operands[i];
- fc++;
+ fixups->fix[fixups->fc].reloc = opcode->operands[i];
+ (fixups->fc)++;
}
/* truncate to the proper number of bits */
@@ -463,84 +435,92 @@ build_insn (opcode, opers)
/* write out a long form instruction */
static void
-write_long (opcode, insn)
+write_long (opcode, insn, fx)
struct d10v_opcode *opcode;
unsigned long insn;
+ Fixups *fx;
{
int i;
char *f = frag_more(4);
insn |= FM11;
- /* printf("INSN: %08x\n",insn); */
+ /* printf("INSN: %08x\n",insn); */
number_to_chars_bigendian (f, insn, 4);
- for (i=0; i<fc; i++)
+ for (i=0; i < fx->fc; i++)
{
- if (get_reloc((struct d10v_operand *)&d10v_operands[fixups[i].reloc]))
+ if (get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].reloc]))
{
/*
printf("fix_new_exp: where:%x size:4\n ",f - frag_now->fr_literal);
- print_expr_1(stdout,&fixups[i].exp);
+ print_expr_1(stdout,&(fx->fix[i].exp));
printf("\n");
*/
-
+
fix_new_exp (frag_now,
f - frag_now->fr_literal,
4,
- &fixups[i].exp,
+ &(fx->fix[i].exp),
1,
- fixups[i].reloc);
+ fx->fix[i].reloc);
}
}
+ fx->fc = 0;
}
+
/* write out a short form instruction by itself */
static void
-write_1_short (opcode, insn)
+write_1_short (opcode, insn, fx)
struct d10v_opcode *opcode;
unsigned long insn;
+ Fixups *fx;
{
char *f = frag_more(4);
int i;
insn |= FM00 | (NOP << 15);
- /* printf("INSN: %08x\n",insn); */
+ /* printf("INSN: %08x\n",insn); */
number_to_chars_bigendian (f, insn, 4);
- for (i=0; i<fc; i++)
+ for (i=0; i < fx->fc; i++)
{
- if (get_reloc((struct d10v_operand *)&d10v_operands[fixups[i].reloc]))
+ if (get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].reloc]))
{
/*
printf("fix_new_exp: where:%x size:4\n ",f - frag_now->fr_literal);
- print_expr_1(stdout,&fixups[i].exp);
+ print_expr_1(stdout,&(fx->fix[i].exp));
printf("\n");
*/
fix_new_exp (frag_now,
f - frag_now->fr_literal,
4,
- &fixups[i].exp,
+ &(fx->fix[i].exp),
1,
- fixups[i].reloc);
+ fx->fix[i].reloc);
}
}
+ fx->fc = 0;
}
/* write out a short form instruction if possible */
/* return number of instructions not written out */
static int
-write_2_short (opcode1, insn1, opcode2, insn2, exec_type)
+write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx)
struct d10v_opcode *opcode1, *opcode2;
unsigned long insn1, insn2;
int exec_type;
+ Fixups *fx;
{
unsigned long insn;
+ char *f;
+ int i,j;
if(opcode1->exec_type == BRANCH_LINK)
{
/* subroutines must be called from 32-bit boundaries */
/* so the return address will be correct */
- write_1_short (opcode1, insn1);
+ write_1_short (opcode1, insn1, fx->next);
return (1);
}
@@ -549,18 +529,22 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type)
case 0:
if (opcode1->unit == IU)
{
+ /* reverse sequential */
insn = FM10 | (insn2 << 15) | insn1;
}
else
{
- insn = FM01 | (insn1 << 15) | insn2;
+ insn = FM01 | (insn1 << 15) | insn2;
+ fx = fx->next;
}
break;
case 1: /* parallel */
insn = FM00 | (insn1 << 15) | insn2;
+ fx = fx->next;
break;
case 2: /* sequential */
insn = FM01 | (insn1 << 15) | insn2;
+ fx = fx->next;
break;
case 3: /* reverse sequential */
insn = FM10 | (insn1 << 15) | insn2;
@@ -570,7 +554,37 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type)
}
/* printf("INSN: %08x\n",insn); */
- number_to_chars_bigendian (frag_more(4), insn, 4);
+ f = frag_more(4);
+ number_to_chars_bigendian (f, insn, 4);
+
+for (j=0; j<2; j++)
+ {
+ bfd_reloc_code_real_type reloc;
+ for (i=0; i < fx->fc; i++)
+ {
+ reloc = get_reloc((struct d10v_operand *)&d10v_operands[fx->fix[i].reloc]);
+ if (reloc)
+ {
+ if ( (reloc == BFD_RELOC_D10V_10_PCREL_R) && (j == 0) )
+ fx->fix[i].reloc |= 1024;
+
+ /*
+ printf("fix_new_exp: where:%x reloc:%d\n ",f - frag_now->fr_literal,fx->fix[i].reloc);
+ print_expr_1(stdout,&(fx->fix[i].exp));
+ printf("\n");
+ */
+ fix_new_exp (frag_now,
+ f - frag_now->fr_literal,
+ 4,
+ &(fx->fix[i].exp),
+ 1,
+ fx->fix[i].reloc);
+ }
+ }
+ fx->fc = 0;
+ fx = fx->next;
+ }
+
return (0);
}
@@ -583,6 +597,8 @@ write_2_short (opcode1, insn1, opcode2, insn2, exec_type)
static unsigned long prev_insn;
static struct d10v_opcode *prev_opcode = 0;
+static subsegT prev_subseg;
+static segT prev_seg;
void
md_assemble (str)
@@ -594,8 +610,7 @@ md_assemble (str)
char *str2;
/* printf("md_assemble: str=%s\n",str); */
- fc = 0;
-
+
/* look for the special multiple instruction seperators */
str2 = strstr (str, "||");
if (str2)
@@ -622,10 +637,11 @@ md_assemble (str)
/* if two instructions are present and we already have one saved
then first write it out */
if (prev_opcode)
- write_1_short (prev_opcode, prev_insn);
+ write_1_short (prev_opcode, prev_insn, fixups->next);
/* assemble first instruction and save it */
prev_insn = do_assemble (str, &prev_opcode);
+ fixups = fixups->next;
str = str2 + 2;
}
@@ -638,15 +654,15 @@ md_assemble (str)
as_fatal("Unable to mix instructions as specified");
if (prev_opcode)
{
- write_1_short (prev_opcode, prev_insn);
+ write_1_short (prev_opcode, prev_insn, fixups->next);
prev_opcode = NULL;
}
- write_long (opcode, insn);
+ write_long (opcode, insn, fixups);
prev_opcode = NULL;
return;
}
- if (prev_opcode && (write_2_short (prev_opcode, prev_insn, opcode, insn, t) == 0))
+ if (prev_opcode && (write_2_short (prev_opcode, prev_insn, opcode, insn, t, fixups) == 0))
{
/* no instructions saved */
prev_opcode = NULL;
@@ -658,6 +674,9 @@ md_assemble (str)
/* save off last instruction so it may be packed on next pass */
prev_opcode = opcode;
prev_insn = insn;
+ prev_seg = now_seg;
+ prev_subseg = now_subseg;
+ fixups = fixups->next;
}
}
@@ -675,7 +694,7 @@ do_assemble (str, opcode)
expressionS myops[6];
unsigned long insn;
- /* printf("do_assemble: str=%s\n",str);*/
+ /* printf("do_assemble: str=%s\n",str); */
/* Drop leading whitespace */
while (*str == ' ')
@@ -780,7 +799,9 @@ do_assemble (str, opcode)
if (!(d10v_operands[(*opcode)->operands[i]].flags & OPERAND_REG))
{
myops[i].X_op = O_symbol;
+ myops[i].X_add_symbol = symbol_find_or_make ((char *)myops[i].X_op_symbol);
myops[i].X_add_number = 0;
+ myops[i].X_op_symbol = NULL;
/* FIXME create a fixup */
}
}
@@ -849,6 +870,7 @@ md_apply_fix3 (fixp, valuep, seg)
char *where;
unsigned long insn;
int op_type;
+ int left=0;
if (fixp->fx_addsy == (symbolS *) NULL)
{
@@ -873,20 +895,25 @@ md_apply_fix3 (fixp, valuep, seg)
}
}
- /* printf("md_apply_fix: value=0x%x type=%d\n", value, fixp->fx_r_type); */
+ /* printf("md_apply_fix: value=0x%x type=%d\n", value, fixp->fx_r_type); */
op_type = fixp->fx_r_type;
- fixp->fx_r_type = get_reloc((struct d10v_operand *)&d10v_operands[op_type]);
-
- /* printf("reloc=%d\n",fixp->fx_r_type); */
+ if (op_type & 1024)
+ {
+ op_type -= 1024;
+ fixp->fx_r_type = BFD_RELOC_D10V_10_PCREL_L;
+ left = 1;
+ }
+ else
+ fixp->fx_r_type = get_reloc((struct d10v_operand *)&d10v_operands[op_type]);
/* Fetch the instruction, insert the fully resolved operand
value, and stuff the instruction back again. */
where = fixp->fx_frag->fr_literal + fixp->fx_where;
insn = bfd_getb32 ((unsigned char *) where);
- /* printf(" insn=%x value=%x\n",insn,value); */
+ /* printf(" insn=%x value=%x\n",insn,value); */
- insn = d10v_insert_operand (insn, op_type, (offsetT) value);
+ insn = d10v_insert_operand (insn, op_type, (offsetT) value, left);
/* printf(" new insn=%x\n",insn); */
@@ -899,29 +926,24 @@ md_apply_fix3 (fixp, valuep, seg)
return 1;
}
-/* This is called after the assembler has finished parsing the input
- file. Because the D10V assembler sometimes saves short instructions
- to see if it can package them with the next instruction, there may
- be a short instruction that still needs written. */
-int md_after_pass()
-{
- if (prev_opcode)
- {
- write_1_short (prev_opcode, prev_insn);
- prev_opcode = NULL;
- }
-}
-
-
-/* there is a label to be defined. Any saved instruction must
- be written out. */
+/* d10v_cleanup() is called after the assembler has finished parsing the input
+ file or after a label is defined. Because the D10V assembler sometimes saves short
+ instructions to see if it can package them with the next instruction, there may
+ be a short instruction that still needs written. */
int
-start_label()
+d10v_cleanup()
{
+ segT seg;
+ subsegT subseg;
+
if (prev_opcode)
{
- write_1_short (prev_opcode, prev_insn);
+ seg = now_seg;
+ subseg = now_subseg;
+ subseg_set (prev_seg, prev_subseg);
+ write_1_short (prev_opcode, prev_insn, fixups);
+ subseg_set (seg, subseg);
prev_opcode = NULL;
}
return 1;
diff --git a/gas/config/tc-d10v.h b/gas/config/tc-d10v.h
index a792bb4..3f50eef 100644
--- a/gas/config/tc-d10v.h
+++ b/gas/config/tc-d10v.h
@@ -46,12 +46,10 @@
/* We don't need to handle .word strangely. */
#define WORKING_DOT_WORD
-
#define md_number_to_chars number_to_chars_bigendian
-#define md_after_pass_hook md_after_pass
-
-extern int start_label PARAMS ((void));
-#define TC_START_LABEL(ch, ptr) (ch == ':' && start_label())
+int d10v_cleanup PARAMS ((void));
+#define md_after_pass_hook() d10v_cleanup()
+#define TC_START_LABEL(ch, ptr) (ch == ':' && d10v_cleanup())