#include "as.h"
#include "safe-ctype.h"
#include "obstack.h"
typedef unsigned char byte;
typedef byte tahoe_opcodeT;
#define TIT_MAX_OPERANDS (4)
struct top
{
int top_ndx;
int top_reg;
byte top_mode;
char top_access;
char top_width;
char * top_error;
segT seg_of_operand;
expressionS exp_of_operand;
byte top_dispsize;
};
#define TAHOE_DIRECT_REG (0x50)
#define TAHOE_REG_DEFERRED (0x60)
#define TAHOE_REG_DISP (0xE0)
#define TAHOE_REG_DISP_DEFERRED (0xF0)
#define TAHOE_IMMEDIATE (0x8F)
#define TAHOE_IMMEDIATE_BYTE (0x88)
#define TAHOE_IMMEDIATE_WORD (0x89)
#define TAHOE_IMMEDIATE_LONGWORD (0x8F)
#define TAHOE_ABSOLUTE_ADDR (0x9F)
#define TAHOE_DISPLACED_RELATIVE (0xEF)
#define TAHOE_DISP_REL_DEFERRED (0xFF)
#define TAHOE_AUTO_DEC (0x7E)
#define TAHOE_AUTO_INC (0x8E)
#define TAHOE_AUTO_INC_DEFERRED (0x9E)
#define TAHOE_WIDTH_ALWAYS_JUMP '-'
#define TAHOE_WIDTH_CONDITIONAL_JUMP '?'
#define TAHOE_WIDTH_BIG_REV_JUMP '!'
#define TAHOE_WIDTH_BIG_NON_REV_JUMP ':'
#define TAHOE_JMP (0x71)
#define TAHOE_PC_REL_LONG (0xEF)
#define TAHOE_BRB (0x11)
#define TAHOE_BRW (0x13)
#define TAHOE_PC_OR_BYTE (0xA0)
#define TAHOE_PC_OR_WORD (0xC0)
#define TAHOE_PC_OR_LONG (0xE0)
struct tit
{
tahoe_opcodeT tit_opcode;
byte tit_operands;
struct top tit_operand[TIT_MAX_OPERANDS];
char *tit_error;
};
#include "opcode/tahoe.h"
long omagic = OMAGIC;
const char comment_chars[] = "#;";
const char line_comment_chars[] = "#";
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "df";
static struct tit t;
void float_cons ();
const pseudo_typeS md_pseudo_table[] =
{
{"dfloat", float_cons, 'd'},
{"ffloat", float_cons, 'f'},
{0}
};
#define BF (1+ 127)
#define BB (1+-128)
#define WF (2+ 32767)
#define WB (2+-32768)
#define C(a,b) ENCODE_RELAX(a,b)
#define ENCODE_RELAX(what,length) (((what) << 2) + (length))
#define RELAX_STATE(s) ((s) >> 2)
#define RELAX_LENGTH(s) ((s) & 3)
#define STATE_ALWAYS_BRANCH (1)
#define STATE_CONDITIONAL_BRANCH (2)
#define STATE_BIG_REV_BRANCH (3)
#define STATE_BIG_NON_REV_BRANCH (4)
#define STATE_PC_RELATIVE (5)
#define STATE_BYTE (0)
#define STATE_WORD (1)
#define STATE_LONG (2)
#define STATE_UNDF (3)
const relax_typeS md_relax_table[] =
{
{
1, 1, 0, 0
},
{
1, 1, 0, 0
},
{
1, 1, 0, 0
},
{
1, 1, 0, 0
},
{
BF, BB, 1, C (1, 1)
},
{
WF, WB, 2, C (1, 2)
},
{
0, 0, 5, 0
},
{
1, 1, 0, 0
},
{
BF, BB, 1, C (2, 1)
},
{
WF + 2, WB + 2, 4, C (2, 2)
},
{
0, 0, 7, 0
},
{
1, 1, 0, 0
},
{
1, 1, 0, 0
},
{
WF, WB, 2, C (3, 2)
},
{
0, 0, 8, 0
},
{
1, 1, 0, 0
},
{
1, 1, 0, 0
},
{
WF, WB, 2, C (4, 2)
},
{
0, 0, 10, 0
},
{
1, 1, 0, 0
},
{
BF + 1, BB + 1, 2, C (5, 1)
},
{
WF + 1, WB + 1, 3, C (5, 2)
},
{
0, 0, 5, 0
},
{
1, 1, 0, 0
},
};
#undef C
#undef BF
#undef BB
#undef WF
#undef WB
static struct hash_control *op_hash;
void
md_begin ()
{
struct tot *tP;
char *errorval = 0;
int synthetic_too = 1;
op_hash = hash_new ();
for (tP = totstrs; *tP->name && !errorval; tP++)
errorval = hash_insert (op_hash, tP->name, &tP->detail);
if (synthetic_too)
for (tP = synthetic_totstrs; *tP->name && !errorval; tP++)
errorval = hash_insert (op_hash, tP->name, &tP->detail);
if (errorval)
as_fatal (errorval);
}
const char *md_shortopts = "ad:STt:V";
struct option md_longopts[] = {
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
int
md_parse_option (c, arg)
int c;
char *arg;
{
switch (c)
{
case 'a':
as_warn (_("The -a option doesn't exist. (Despite what the man page says!"));
break;
case 'd':
as_warn (_("Displacement length %s ignored!"), arg);
break;
case 'S':
as_warn (_("SYMBOL TABLE not implemented"));
break;
case 'T':
as_warn (_("TOKEN TRACE not implemented"));
break;
case 't':
as_warn (_("I don't need or use temp. file \"%s\"."), arg);
break;
case 'V':
as_warn (_("I don't use an interpass file! -V ignored"));
break;
default:
return 0;
}
return 1;
}
void
md_show_usage (stream)
FILE *stream;
{
fprintf (stream, _("\
Tahoe options:\n\
-a ignored\n\
-d LENGTH ignored\n\
-J ignored\n\
-S ignored\n\
-t FILE ignored\n\
-T ignored\n\
-V ignored\n"));
}
void
md_number_to_chars (con, value, nbytes)
char con[];
valueT value;
int nbytes;
{
number_to_chars_bigendian (con, value, nbytes);
}
#ifdef comment
void
md_number_to_imm (con, value, nbytes)
char con[];
long int value;
int nbytes;
{
md_number_to_chars (con, value, nbytes);
}
#endif
void
md_apply_fix3 (fixP, valP, seg)
fixS *fixP ATTRIBUTE_UNUSED;
valueT * valP ATTRIBUTE_UNUSED;
segT seg ATTRIBUTE_UNUSED:
{
know (0);
}
void
md_number_to_disp (con, value, nbytes)
char con[];
long int value;
int nbytes;
{
md_number_to_chars (con, value, nbytes);
}
void
md_number_to_field (con, value, nbytes)
char con[];
long int value;
int nbytes;
{
md_number_to_chars (con, value, nbytes);
}
#if comment
void
md_ri_to_chars (ri_p, ri)
struct relocation_info *ri_p, ri;
{
byte the_bytes[sizeof (struct relocation_info)];
md_number_to_chars (the_bytes, ri.r_address, sizeof (ri.r_address));
the_bytes[4] = (ri.r_symbolnum >> 16) & 0x0ff;
the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff;
the_bytes[6] = ri.r_symbolnum & 0x0ff;
the_bytes[7] = (((ri.r_extern << 4) & 0x10) | ((ri.r_length << 5) & 0x60) |
((ri.r_pcrel << 7) & 0x80)) & 0xf0;
bcopy (the_bytes, (char *) ri_p, sizeof (struct relocation_info));
}
#endif
void
tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
char *where;
fixS *fixP;
relax_addressT segment_address_in_file;
{
long r_symbolnum;
know (fixP->fx_addsy != NULL);
md_number_to_chars (where,
fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
4);
r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
? S_GET_TYPE (fixP->fx_addsy)
: fixP->fx_addsy->sy_number);
where[4] = (r_symbolnum >> 16) & 0x0ff;
where[5] = (r_symbolnum >> 8) & 0x0ff;
where[6] = r_symbolnum & 0x0ff;
where[7] = (((is_pcrel (fixP) << 7) & 0x80)
| ((((fixP->fx_type == FX_8 || fixP->fx_type == FX_PCREL8
? 0
: (fixP->fx_type == FX_16 || fixP->fx_type == FX_PCREL16
? 1
: (fixP->fx_type == FX_32 || fixP->fx_type == FX_PCREL32
? 2
: 42)))) << 5) & 0x60)
| ((!S_IS_DEFINED (fixP->fx_addsy) << 4) & 0x10));
}
int md_short_jump_size = 3;
void
md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
char *ptr;
addressT from_addr, to_addr;
fragS *frag;
symbolS *to_symbol;
{
valueT offset;
offset = to_addr - (from_addr + 1);
*ptr++ = TAHOE_BRW;
md_number_to_chars (ptr, offset, 2);
}
int md_long_jump_size = 6;
const int md_reloc_size = 8;
void
md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
char *ptr;
addressT from_addr, to_addr;
fragS *frag;
symbolS *to_symbol;
{
valueT offset;
offset = to_addr - (from_addr + 4);
*ptr++ = TAHOE_JMP;
*ptr++ = TAHOE_PC_REL_LONG;
md_number_to_chars (ptr, offset, 4);
}
int
md_estimate_size_before_relax (fragP, segment_type)
register fragS *fragP;
segT segment_type;
{
if (RELAX_LENGTH (fragP->fr_subtype) == STATE_UNDF)
{
if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
{
char *p;
int old_fr_fix;
old_fr_fix = fragP->fr_fix;
p = fragP->fr_literal + old_fr_fix;
switch (RELAX_STATE (fragP->fr_subtype))
{
case STATE_PC_RELATIVE:
*p |= TAHOE_PC_OR_LONG;
fragP->fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
break;
case STATE_CONDITIONAL_BRANCH:
*fragP->fr_opcode ^= 0x10;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = TAHOE_PC_REL_LONG;
fragP->fr_fix += 1 + 1 + 1 + 4;
fix_new (fragP, old_fr_fix + 3, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
break;
case STATE_BIG_REV_BRANCH:
*fragP->fr_opcode ^= 0x10;
*p++ = 0;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = TAHOE_PC_REL_LONG;
fragP->fr_fix += 2 + 2 + 4;
fix_new (fragP, old_fr_fix + 4, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
break;
case STATE_BIG_NON_REV_BRANCH:
*p++ = 2;
*p++ = 0;
*p++ = TAHOE_BRB;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = TAHOE_PC_REL_LONG;
fragP->fr_fix += 2 + 2 + 2 + 4;
fix_new (fragP, old_fr_fix + 6, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
break;
case STATE_ALWAYS_BRANCH:
*fragP->fr_opcode = TAHOE_JMP;
*p++ = TAHOE_PC_REL_LONG;
fragP->fr_fix += 1 + 4;
fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol,
fragP->fr_offset, FX_PCREL32, NULL);
break;
default:
abort ();
}
frag_wane (fragP);
return fragP->fr_fix - old_fr_fix;
}
switch (RELAX_STATE (fragP->fr_subtype))
{
case STATE_PC_RELATIVE:
fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE);
break;
case STATE_CONDITIONAL_BRANCH:
fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
break;
case STATE_BIG_REV_BRANCH:
fragP->fr_subtype = ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD);
break;
case STATE_BIG_NON_REV_BRANCH:
fragP->fr_subtype = ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD);
break;
case STATE_ALWAYS_BRANCH:
fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE);
break;
}
}
if (fragP->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0]))
abort ();
return md_relax_table[fragP->fr_subtype].rlx_length;
}
void
md_convert_frag (headers, seg, fragP)
object_headers *headers;
segT seg;
register fragS *fragP;
{
register char *addressP;
register char *opcodeP;
register short int extension = 0;
register symbolS *symbolP;
register long int where;
register long int address_of_var;
register long int target_address;
know (fragP->fr_type == rs_machine_dependent);
where = fragP->fr_fix;
addressP = fragP->fr_literal + where;
opcodeP = fragP->fr_opcode;
symbolP = fragP->fr_symbol;
know (symbolP);
target_address = S_GET_VALUE (symbolP) + fragP->fr_offset;
address_of_var = fragP->fr_address + where;
switch (fragP->fr_subtype)
{
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE):
*addressP++ |= TAHOE_PC_OR_BYTE;
*addressP = target_address - (address_of_var + 2);
extension = 2;
break;
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD):
*addressP++ |= TAHOE_PC_OR_WORD;
md_number_to_chars (addressP, target_address - (address_of_var + 3), 2);
extension = 3;
break;
case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG):
*addressP++ |= TAHOE_PC_OR_LONG;
md_number_to_chars (addressP, target_address - (address_of_var + 5), 4);
extension = 5;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
*addressP = target_address - (address_of_var + 1);
extension = 1;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
*opcodeP ^= 0x10;
*addressP++ = 3;
*addressP++ = TAHOE_BRW;
md_number_to_chars (addressP, target_address - (address_of_var + 4), 2);
extension = 4;
break;
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_LONG):
*opcodeP ^= 0x10;
*addressP++ = 6;
*addressP++ = TAHOE_JMP;
*addressP++ = TAHOE_PC_REL_LONG;
md_number_to_chars (addressP, target_address, 4);
extension = 7;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE):
*addressP = target_address - (address_of_var + 1);
extension = 1;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD):
*opcodeP = TAHOE_BRW;
md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
extension = 2;
break;
case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG):
*opcodeP = TAHOE_JMP;
*addressP++ = TAHOE_PC_REL_LONG;
md_number_to_chars (addressP, target_address - (address_of_var + 5), 4);
extension = 5;
break;
case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD):
md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
extension = 2;
break;
case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_LONG):
*opcodeP ^= 0x10;
*addressP++ = 0;
*addressP++ = 6;
*addressP++ = TAHOE_JMP;
*addressP++ = TAHOE_PC_REL_LONG;
md_number_to_chars (addressP, target_address, 4);
extension = 8;
break;
case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD):
md_number_to_chars (addressP, target_address - (address_of_var + 2), 2);
extension = 2;
break;
case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_LONG):
*addressP++ = 0;
*addressP++ = 2;
*addressP++ = TAHOE_BRB;
*addressP++ = 6;
*addressP++ = TAHOE_JMP;
*addressP++ = TAHOE_PC_REL_LONG;
md_number_to_chars (addressP, target_address, 4);
extension = 10;
break;
default:
BAD_CASE (fragP->fr_subtype);
break;
}
fragP->fr_fix += extension;
}
#define FP_REG 13
#define SP_REG 14
#define PC_REG 15
#define BIGGESTREG PC_REG
int
tahoe_reg_parse (start)
char **start;
{
register char *regpoint = *start;
register int regnum = -1;
switch (*regpoint++)
{
case '%':
case 'R':
case 'r':
if (ISDIGIT (*regpoint))
{
regnum = *regpoint++ - '0';
if ((regnum == 1) && ISDIGIT (*regpoint))
{
regnum = 10 + (*regpoint++ - '0');
if (regnum > BIGGESTREG)
{
regnum = -1;
}
}
}
break;
case 'F':
case 'f':
switch (*regpoint++)
{
case 'p':
case 'P':
regnum = FP_REG;
}
break;
case 's':
case 'S':
switch (*regpoint++)
{
case 'p':
case 'P':
regnum = SP_REG;
}
break;
case 'p':
case 'P':
switch (*regpoint++)
{
case 'c':
case 'C':
regnum = PC_REG;
}
break;
}
if (regnum != -1)
{
*start = regpoint;
}
return regnum;
}
void
tip_op (optex, topP)
char *optex;
struct top *topP;
{
int mode = 0;
char segfault = *optex;
char *point = optex + 1;
char *end;
int reg = -1;
int imreg = -1;
int ndx = -1;
char dec_inc = ' ';
int immediate = 0;
int call_width = 0;
int abs_width = 0;
int com_width = 0;
int deferred = 0;
byte disp_size = 0;
char *op_bad = "";
char *tp, *temp, c;
char access = topP->top_access;
char width = topP->top_width;
int really_none = 0;
expressionS *expP;
if (access == 'b')
com_width = (width == 'b' ? 1 :
(width == 'w' ? 2 :
(width == 'l' ? 4 : 0)));
*optex = '\0';
if (*point == '*')
{
deferred = 1;
point++;
}
if (*point != '\0' && ((point[1] == '^') || (point[1] == '`')))
switch (*point)
{
case 'b':
case 'B':
case 'w':
case 'W':
case 'l':
case 'L':
if (com_width)
as_warn (_("Casting a branch displacement is bad form, and is ignored."));
else
{
c = TOLOWER (*point);
call_width = ((c == 'b') ? 1 :
((c == 'w') ? 2 : 4));
}
point += 2;
break;
}
if (*point == '$')
{
immediate = 1;
point++;
}
for (end = point; *end != '\0'; end++)
;
if (end != point)
end--;
if (end > point && *end == ' ' && end[-1] != '\'')
end--;
if ((*end == ']') && (end[-1] != '\''))
{
temp = end;
for (--end; (*end != '[' && end != point); end--)
;
if (*end == '[')
{
tp = end + 1;
ndx = tahoe_reg_parse (&tp);
if (tp != temp)
{
ndx = -1;
}
else
{
end--;
}
if (ndx == -1)
{
op_bad = _("Couldn't parse the [index] in this operand.");
end = point;
}
}
else
{
op_bad = _("Couldn't find the opening '[' for the index of this operand.");
end = point;
}
}
if (*end == '+')
{
dec_inc = '+';
end--;
}
if ((*end == ')') && (end[-1] != '\''))
{
temp = end;
for (--end; (*end != '(' && end != point); end--)
;
if (*end == '(')
{
tp = end + 1;
reg = tahoe_reg_parse (&tp);
if (tp != temp)
{
reg = -1;
end = temp;
}
else
{
end--;
}
}
else
{
op_bad = _("Couldn't find the opening '(' for the deref of this operand.");
end = point;
}
}
if (*end == '-')
{
if (dec_inc != ' ')
{
op_bad = _("Operand can't be both pre-inc and post-dec.");
end = point;
}
else
{
dec_inc = '-';
end--;
}
}
c = end[1];
end[1] = '\0';
tp = point;
imreg = tahoe_reg_parse (&point);
if (*point != '\0')
{
point = tp;
imreg = -1;
}
if (imreg != -1 && reg != -1)
op_bad = _("I parsed 2 registers in this operand.");
if (*op_bad == '\0')
{
input_line_pointer = point;
expP = &(topP->exp_of_operand);
topP->seg_of_operand = expression (expP);
switch (expP->X_op)
{
case O_absent:
expP->X_op = O_constant;
expP->X_add_number = 0;
really_none = 1;
case O_constant:
expP->X_add_symbol = NULL;
expP->X_op_symbol = NULL;
abs_width =
((((expP->X_add_number & 0xFFFFFF80) == 0) ||
((expP->X_add_number & 0xFFFFFF80) == 0xFFFFFF80)) ? 1 :
(((expP->X_add_number & 0xFFFF8000) == 0) ||
((expP->X_add_number & 0xFFFF8000) == 0xFFFF8000)) ? 2 : 4);
case O_symbol:
break;
default:
need_pass_2 = 1;
op_bad = _("Can't relocate expression error.");
break;
case O_big:
op_bad = _("Expression is too large for a 32 bits.");
break;
}
if (*input_line_pointer != '\0')
{
op_bad = _("Junk at end of expression.");
}
}
end[1] = c;
*optex = segfault;
disp_size = (call_width ? call_width :
(com_width ? com_width :
abs_width ? abs_width : 0));
if (*op_bad == '\0')
{
if (imreg != -1)
{
mode = TAHOE_DIRECT_REG;
if (deferred || immediate || (dec_inc != ' ') ||
(reg != -1) || !really_none)
op_bad = _("Syntax error in direct register mode.");
else if (ndx != -1)
op_bad = _("You can't index a register in direct register mode.");
else if (imreg == SP_REG && access == 'r')
op_bad =
_("SP can't be the source operand with direct register addressing.");
else if (access == 'a')
op_bad = _("Can't take the address of a register.");
else if (access == 'b')
op_bad = _("Direct Register can't be used in a branch.");
else if (width == 'q' && ((imreg % 2) || (imreg > 13)))
op_bad = _("For quad access, the register must be even and < 14.");
else if (call_width)
op_bad = _("You can't cast a direct register.");
if (*op_bad == '\0')
{
if (width == 'q' && imreg == 12)
as_warn (_("Using reg 14 for quadwords can tromp the FP register."));
reg = imreg;
}
}
else if (dec_inc == '-')
{
mode = TAHOE_AUTO_DEC;
if (deferred || immediate || !really_none)
op_bad = _("Syntax error in auto-dec mode.");
else if (ndx != -1)
op_bad = _("You can't have an index auto dec mode.");
else if (access == 'r')
op_bad = _("Auto dec mode cant be used for reading.");
else if (reg != SP_REG)
op_bad = _("Auto dec only works of the SP register.");
else if (access == 'b')
op_bad = _("Auto dec can't be used in a branch.");
else if (width == 'q')
op_bad = _("Auto dec won't work with quadwords.");
}
else if (dec_inc == '+')
{
if (immediate || !really_none)
op_bad = _("Syntax error in one of the auto-inc modes.");
else if (deferred)
{
mode = TAHOE_AUTO_INC_DEFERRED;
if (reg != SP_REG)
op_bad = _("Auto inc deferred only works of the SP register.");
else if (ndx != -1)
op_bad = _("You can't have an index auto inc deferred mode.");
else if (access == 'b')
op_bad = _("Auto inc can't be used in a branch.");
}
else
{
mode = TAHOE_AUTO_INC;
if (access == 'm' || access == 'w')
op_bad = _("You can't write to an auto inc register.");
else if (reg != SP_REG)
op_bad = _("Auto inc only works of the SP register.");
else if (access == 'b')
op_bad = _("Auto inc can't be used in a branch.");
else if (width == 'q')
op_bad = _("Auto inc won't work with quadwords.");
else if (ndx != -1)
op_bad = _("You can't have an index in auto inc mode.");
}
}
else if (reg != -1)
{
if ((ndx != -1) && (reg == SP_REG))
op_bad = _("You can't index the sp register.");
if (deferred)
{
mode = TAHOE_REG_DISP_DEFERRED;
if (immediate)
op_bad = _("Syntax error in register displaced mode.");
}
else if (really_none)
{
mode = TAHOE_REG_DEFERRED;
}
else
{
mode = TAHOE_REG_DISP;
}
}
else
{
if (really_none)
op_bad = _("An offest is needed for this operand.");
if (deferred && immediate)
{
mode = TAHOE_ABSOLUTE_ADDR;
disp_size = 4;
}
else if (immediate)
{
mode = TAHOE_IMMEDIATE;
if (ndx != -1)
op_bad = _("You can't index a register in immediate mode.");
if (access == 'a')
op_bad = _("Immediate access can't be used as an address.");
}
else if (deferred)
{
mode = TAHOE_DISP_REL_DEFERRED;
}
else
{
mode = TAHOE_DISPLACED_RELATIVE;
}
}
}
topP->top_ndx = ndx;
topP->top_reg = reg;
topP->top_mode = mode;
topP->top_error = op_bad;
topP->top_dispsize = disp_size;
}
static void
tip (titP, instring)
struct tit *titP;
char *instring;
{
register struct tot_wot *twP = NULL;
register char *p;
register char *q;
register unsigned char count;
register struct top *operandp;
register char *alloperr = "";
register char c;
char *save_input_line_pointer;
if (*instring == ' ')
++instring;
for (p = instring; *p && *p != ' '; p++)
;
if (p == instring)
{
titP->tit_error = _("No operator");
count = 0;
titP->tit_opcode = 0;
}
else
{
c = *p;
*p = '\0';
twP = (struct tot_wot *) hash_find (op_hash, instring);
*p = c;
if (twP == 0)
{
titP->tit_error = _("Unknown operator");
count = 0;
titP->tit_opcode = 0;
}
else
{
count = 0;
instring = p + (*p != '\0');
save_input_line_pointer = input_line_pointer;
for (p = twP->args, operandp = titP->tit_operand;
!*alloperr && *p;
operandp++, p += 2)
{
if (!p[1])
as_fatal (_("Compiler bug: ODD number of bytes in arg structure %s."),
twP->args);
else if (*instring)
{
for (q = instring; (*q != ',' && *q != '\0'); q++)
{
if (*q == '\'' && q[1] != '\0')
q++;
}
c = *q;
*q = '\0';
operandp->top_access = p[0];
operandp->top_width = p[1];
tip_op (instring - 1, operandp);
*q = c;
if (*(operandp->top_error))
{
alloperr = operandp->top_error;
}
instring = q + (c ? 1 : 0);
count++;
}
else
alloperr = _("Not enough operands");
}
input_line_pointer = save_input_line_pointer;
if (!*alloperr)
{
if (*instring == ' ')
instring++;
if (*instring)
alloperr = _("Too many operands");
}
titP->tit_error = alloperr;
}
}
titP->tit_opcode = twP->code;
titP->tit_operands = count;
}
void
md_assemble (instruction_string)
char *instruction_string;
{
char *p;
register struct top *operandP;
register expressionS *expP;
segT to_seg;
register valueT this_add_number;
register symbolS *this_add_symbol;
char *opcodeP;
int dispsize;
int is_undefined;
int pc_rel;
tip (&t, instruction_string);
if (*t.tit_error)
{
as_warn (_("Ignoring statement due to \"%s\""), t.tit_error);
}
else
{
opcodeP = frag_more (1);
*opcodeP = t.tit_opcode;
for (operandP = t.tit_operand;
operandP < t.tit_operand + t.tit_operands;
operandP++)
{
expP = &(operandP->exp_of_operand);
if (operandP->top_ndx >= 0)
{
FRAG_APPEND_1_CHAR (0x40 + operandP->top_ndx);
}
this_add_number = expP->X_add_number;
this_add_symbol = expP->X_add_symbol;
to_seg = operandP->seg_of_operand;
know (to_seg == SEG_UNKNOWN || \
to_seg == SEG_ABSOLUTE || \
to_seg == SEG_DATA || \
to_seg == SEG_TEXT || \
to_seg == SEG_BSS);
is_undefined = (to_seg == SEG_UNKNOWN);
dispsize = operandP->top_dispsize;
pc_rel = 0;
if (operandP->top_access == 'b')
{
if (to_seg == now_seg || is_undefined)
{
if (dispsize)
{
p = frag_more (dispsize);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
size_to_fx (dispsize, 1),
NULL);
}
else
{
switch (operandP->top_width)
{
case TAHOE_WIDTH_CONDITIONAL_JUMP:
frag_var (rs_machine_dependent, 7, 1,
ENCODE_RELAX (STATE_CONDITIONAL_BRANCH,
is_undefined ? STATE_UNDF : STATE_BYTE),
this_add_symbol, this_add_number, opcodeP);
break;
case TAHOE_WIDTH_ALWAYS_JUMP:
frag_var (rs_machine_dependent, 5, 1,
ENCODE_RELAX (STATE_ALWAYS_BRANCH,
is_undefined ? STATE_UNDF : STATE_BYTE),
this_add_symbol, this_add_number, opcodeP);
break;
case TAHOE_WIDTH_BIG_REV_JUMP:
frag_var (rs_machine_dependent, 8, 2,
ENCODE_RELAX (STATE_BIG_REV_BRANCH,
is_undefined ? STATE_UNDF : STATE_WORD),
this_add_symbol, this_add_number,
opcodeP);
break;
case TAHOE_WIDTH_BIG_NON_REV_JUMP:
frag_var (rs_machine_dependent, 10, 2,
ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH,
is_undefined ? STATE_UNDF : STATE_WORD),
this_add_symbol, this_add_number,
opcodeP);
break;
default:
as_fatal (_("Compliler bug: Got a case (%d) I wasn't expecting."),
operandP->top_width);
}
}
}
else
{
switch (operandP->top_width)
{
case TAHOE_WIDTH_CONDITIONAL_JUMP:
*opcodeP ^= 0x10;
p = frag_more (7);
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = (operandP->top_mode ==
TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
TAHOE_PC_REL_LONG);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
(to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
break;
case TAHOE_WIDTH_ALWAYS_JUMP:
*opcodeP = TAHOE_JMP;
p = frag_more (5);
*p++ = (operandP->top_mode ==
TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
TAHOE_PC_REL_LONG);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
(to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
break;
case TAHOE_WIDTH_BIG_REV_JUMP:
p = frag_more (8);
*opcodeP ^= 0x10;
*p++ = 0;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = (operandP->top_mode ==
TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
TAHOE_PC_REL_LONG);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
(to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
break;
case TAHOE_WIDTH_BIG_NON_REV_JUMP:
p = frag_more (10);
*p++ = 0;
*p++ = 2;
*p++ = TAHOE_BRB;
*p++ = 6;
*p++ = TAHOE_JMP;
*p++ = (operandP->top_mode ==
TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
TAHOE_PC_REL_LONG);
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
(to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
break;
case 'b':
case 'w':
as_warn (_("Real branch displacements must be expressions."));
break;
default:
as_fatal (_("Complier error: I got an unknown synthetic branch :%c"),
operandP->top_width);
break;
}
}
}
else
{
switch (operandP->top_mode)
{
case TAHOE_AUTO_DEC:
case TAHOE_AUTO_INC:
case TAHOE_AUTO_INC_DEFERRED:
FRAG_APPEND_1_CHAR (operandP->top_mode);
break;
case TAHOE_DIRECT_REG:
case TAHOE_REG_DEFERRED:
FRAG_APPEND_1_CHAR (operandP->top_mode + operandP->top_reg);
break;
case TAHOE_ABSOLUTE_ADDR:
know ((this_add_symbol == NULL));
p = frag_more (5);
*p = TAHOE_ABSOLUTE_ADDR;
md_number_to_chars (p + 1, this_add_number, 4);
break;
case TAHOE_IMMEDIATE:
if (this_add_symbol != NULL)
{
p = frag_more (5);
*p++ = TAHOE_IMMEDIATE_LONGWORD;
fix_new (frag_now, p - frag_now->fr_literal,
this_add_symbol, this_add_number,
FX_32, NULL);
}
else
{
if ((unsigned) this_add_number < 0x40)
{
FRAG_APPEND_1_CHAR ((byte) this_add_number);
}
else
{
p = frag_more (dispsize + 1);
switch (dispsize)
{
case 1:
*p++ = TAHOE_IMMEDIATE_BYTE;
*p = (byte) this_add_number;
break;
case 2:
*p++ = TAHOE_IMMEDIATE_WORD;
md_number_to_chars (p, this_add_number, 2);
break;
case 4:
*p++ = TAHOE_IMMEDIATE_LONGWORD;
md_number_to_chars (p, this_add_number, 4);
break;
}
}
}
break;
case TAHOE_DISPLACED_RELATIVE:
case TAHOE_DISP_REL_DEFERRED:
operandP->top_reg = PC_REG;
pc_rel = 1;
case TAHOE_REG_DISP:
case TAHOE_REG_DISP_DEFERRED:
if (operandP->top_mode == TAHOE_DISP_REL_DEFERRED ||
operandP->top_mode == TAHOE_REG_DISP_DEFERRED)
operandP->top_reg += 0x10;
if ((dispsize == 0 && !pc_rel) ||
(to_seg != now_seg && !is_undefined && to_seg != SEG_ABSOLUTE))
dispsize = 4;
if (dispsize == 0)
{
p = frag_var (rs_machine_dependent, 5, 2,
ENCODE_RELAX (STATE_PC_RELATIVE,
is_undefined ? STATE_UNDF : STATE_BYTE),
this_add_symbol, this_add_number, 0);
*p = operandP->top_reg;
}
else
{
p = frag_more (dispsize + 1);
switch (dispsize)
{
case 1:
*p = TAHOE_PC_OR_BYTE + operandP->top_reg;
break;
case 2:
*p = TAHOE_PC_OR_WORD + operandP->top_reg;
break;
case 4:
*p = TAHOE_PC_OR_LONG + operandP->top_reg;
break;
};
fix_new (frag_now, p + 1 - frag_now->fr_literal,
this_add_symbol, this_add_number,
size_to_fx (dispsize, pc_rel), NULL);
}
break;
default:
as_fatal (_("Barf, bad mode %x\n"), operandP->top_mode);
}
}
}
}
}
symbolS *
md_undefined_symbol (name)
char *name;
{
return 0;
}
valueT
md_section_align (segment, size)
segT segment;
valueT size;
{
return ((size + 7) & ~7);
}
long
md_pcrel_from (fixP)
fixS *fixP;
{
return (((fixP->fx_type == FX_8
|| fixP->fx_type == FX_PCREL8)
? 1
: ((fixP->fx_type == FX_16
|| fixP->fx_type == FX_PCREL16)
? 2
: ((fixP->fx_type == FX_32
|| fixP->fx_type == FX_PCREL32)
? 4
: 0))) + fixP->fx_where + fixP->fx_frag->fr_address);
}
int
tc_is_pcrel (fixP)
fixS *fixP;
{
know (0);
return (0);
}