#include <ctype.h>
#define NO_RELOC 0
#include "as.h"
+#include "read.h"
#include "obstack.h"
/* note that this file includes real declarations and thus can only be included by one source file per executable. */
#include "opcode/m68k.h"
+
#ifdef TE_SUN
/* This variable contains the value to write out at the beginning of
the a.out file. The 2<<16 means that this is a 68020 file instead
/* Also note that comments like this one will always work. */
const char line_comment_chars[] = "#";
+const char line_separator_chars[] = "";
+
/* Chars that can be used to separate mant from exp in floating point nums */
const char EXP_CHARS[] = "eE";
#define SHORT 1
#define LONG 2
#define SZ_UNDEF 3
-
-#define BRANCH 1
+#undef BRANCH
+#define ABRANCH 1
#define FBRANCH 2
#define PCREL 3
#define BCC68000 4
*** MSCR otherreg --> Magic
With -l option
5.? AOFF apc@(num) --> *(apc+num) -- empty string and ZPC not allowed here still
+ ?.? DINDR dreg@ --> (dreg) -- cas2 only
examples:
#foo #0x35 #12
ABSL,
MSCR,
REGLST,
+ DINDR
};
FPS,
FPC,
- DRP,
+ DRP, /* 68851 or 68030 MMU regs */
CRP,
CAL,
VAL,
BAC5,
BAC6,
BAC7,
- PSR,
+ PSR, /* aka MMUSR on 68030 (but not MMUSR on 68040)
+ and ACUSR on 68ec030 */
PCSR,
IC, /* instruction cache token */
NC, /* no cache token */
BC, /* both caches token */
+ TT0, /* 68030 access control unit regs */
+ TT1,
};
/* Internal form of an operand. */
unsigned long m_opcode;
short m_opnum;
short m_codenum;
- enum m68k_architecture m_arch;
+ int m_arch;
struct m68k_incant *m_next;
};
+
+
#define getone(x) ((((x)->m_opcode)>>16)&0xffff)
#define gettwo(x) (((x)->m_opcode)&0xffff)
static int try_index(char **s, struct m68k_op *opP);
static void install_gen_operand(int mode, int val);
static void install_operand(int mode, int val);
- void s_bss(void);
+static void s_bss(void);
static void s_data1(void);
static void s_data2(void);
static void s_even(void);
static int try_index();
static void install_gen_operand();
static void install_operand();
-void s_bss();
+static void s_bss();
void s_align_bytes();
static void s_data1();
static void s_data2();
#endif /* not __STDC__ */
-static enum m68k_architecture current_architecture = 0;
+static int current_architecture = 0;
/* BCC68000 is for patching in an extra jmp instruction for long offsets
on the 68000. The 68000 doesn't support long branches with branchs */
{ 1, 1, 0, 0 }, /* that the VAX doesn't either */
{ 1, 1, 0, 0 },
- { (127), (-128), 0, TAB(BRANCH,SHORT)},
- { (32767), (-32768), 2, TAB(BRANCH,LONG) },
+ { (127), (-128), 0, TAB(ABRANCH,SHORT)},
+ { (32767), (-32768), 2, TAB(ABRANCH,LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
};
+/* The mote pseudo ops are put into the opcode table, since they
+ don't start with a . they look like opcodes to gas.
+ */
+extern void obj_coff_section();
+
+const pseudo_typeS mote_pseudo_table[] =
+{
+
+ { "dc.l", cons,4},
+ { "dc", cons,2},
+ { "dc.w", cons,2},
+ { "dc.b", cons,1},
+
+ { "ds.l", s_space,4},
+ { "ds", s_space,2},
+ { "ds.w", s_space,2},
+ { "ds.b", s_space,1},
+
+ { "xdef", s_globl, 0},
+ { "align", s_align_ptwo, 0},
+#ifdef M68KCOFF
+ { "sect", obj_coff_section,0},
+ { "section", obj_coff_section,0},
+#endif
+ 0,
+};
+
/* #define isbyte(x) ((x)>=-128 && (x)<=127) */
/* #define isword(x) ((x)>=-32768 && (x)<=32767) */
* advance the pointer.
*/
-enum _register m68k_reg_parse(ccp)
-register char **ccp;
+enum _register
+m68k_reg_parse(ccp)
+ register char **ccp;
{
char *start = *ccp;
+#ifdef REGISTER_PREFIX
+ if (*start == REGISTER_PREFIX)
+ ++start;
+#endif
+
if (isalpha(*start) && is_name_beginner(*start))
{
char c;
char *p = start;
symbolS *symbolP;
- while (is_part_of_name(c = *p++))
- ;
+ c = *p++;
+ while (isalpha(c) || isdigit(c) || c == '_')
+ {
+ c = *p++;
+ }
+
* -- p = 0;
symbolP = symbol_find(start);
*p = c;
}
#define SKIP_WHITE() { str++; if(*str==' ') str++;}
+#define SKIP_W() { ss++; if(*ss==' ') ss++;}
+
+/* Parse an index specification using Motorola syntax. */
+
+static int
+try_moto_index(s,opP)
+char **s;
+struct m68k_op *opP;
+{
+ register int i;
+ char *ss;
+
+ ss= *s;
+ /* SKIP_W(); */
+ if(*ss==' ') ss++;
+ i=m68k_reg_parse(&ss);
+ if(!(i>=DATA+0 && i<=ADDR+7)) { /* if i is not DATA or ADDR reg */
+ opP->error="Invalid index register";
+ *s=ss;
+ return FAIL;
+ }
+ opP->ireg=i;
+ /* SKIP_W(); */
+ if(*ss==')') {
+ opP->isiz=0;
+ opP->imul=1;
+ SKIP_W();
+ *s=ss;
+ return OK;
+ }
+ if(*ss!='.') {
+ opP->error="Missing . in index register";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ if(mklower(*ss)=='w') opP->isiz=2;
+ else if(mklower(*ss)=='l') opP->isiz=3;
+ else {
+ opP->error="Size spec not .W or .L";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ if(*ss=='.' || *ss=='*') {
+ SKIP_W();
+ switch(*ss) {
+ case '1':
+ case '2':
+ case '4':
+ case '8':
+ opP->imul= *ss-'0';
+ break;
+ default:
+ opP->error="index multiplier not 1, 2, 4 or 8";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ } else opP->imul=1;
+ if(*ss!=')') {
+ opP->error="Missing )";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ *s=ss;
+ return OK;
+}
/*
- * m68k_ip_op := '#' + <anything>
- * | <register> + range_sep + get_regs
+ *
+ * try_index := data_or_address_register + ')' + SKIP_W
+ * | data_or_address_register + ':' + SKIP_W + size_spec + SKIP_W + multiplier + ')' + SKIP_W
+ *
+ * multiplier := <empty>
+ * | ':' + multiplier_number
* ;
*
- * range_sep := '/' | '-' ;
+ * multiplier_number := '1' | '2' | '4' | '8' ;
+ *
+ * size_spec := 'l' | 'L' | 'w' | 'W' ;
*
- * SKIP_WHITE := <empty> | ' ' ;
+ * SKIP_W := <empty> | ' ' ;
*
*/
+static int try_index(s,opP)
+char **s;
+struct m68k_op *opP;
+{
+ register int i;
+ char *ss;
+
+ ss= *s;
+ /* SKIP_W(); */
+ i=m68k_reg_parse(&ss);
+ if(!(i>=DATA+0 && i<=ADDR+7)) { /* if i is not DATA or ADDR reg */
+ *s=ss;
+ return FAIL;
+ }
+ opP->ireg=i;
+ /* SKIP_W(); */
+ if(*ss==')') {
+ opP->isiz=0;
+ opP->imul=1;
+ SKIP_W();
+ *s=ss;
+ return OK;
+ }
+ if(*ss!=':') {
+ opP->error="Missing : in index register";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ switch(*ss) {
+ case 'w':
+ case 'W':
+ opP->isiz=2;
+ break;
+ case 'l':
+ case 'L':
+ opP->isiz=3;
+ break;
+ default:
+ opP->error="Index register size spec not :w or :l";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ if(*ss==':') {
+ SKIP_W();
+ switch(*ss) {
+ case '1':
+ case '2':
+ case '4':
+ case '8':
+ if (cpu_of_arch(current_architecture) < m68020) {
+ opP->error="no index scaling in pre-68020's";
+ *s=ss;
+ return FAIL;
+ }
+ opP->imul= *ss-'0';
+ break;
+ default:
+ opP->error="index multiplier not 1, 2, 4 or 8";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ } else opP->imul=1;
+ if(*ss!=')') {
+ opP->error="Missing )";
+ *s=ss;
+ return FAIL;
+ }
+ SKIP_W();
+ *s=ss;
+ return OK;
+} /* try_index() */
+
+/* Ian Taylor expanded this function to accept both MIT and Motorola
+ syntax. I removed the old comment, since it was wrong. The syntax
+ this accepted even before my changes was complex and undocumented.
+ I mainly added a large case when the operand string does not
+ contain an '@', since the Motorola syntax does not use the '@'
+ character. */
+
int
m68k_ip_op(str,opP)
char *str;
long i;
char *parse_index();
int needp;
+
if (*str==' ') {
str++;
} /* Find the beginning of the string */
return FAIL;
} /* Out of gas */
- for(strend = str; *strend; strend++) ;;
-
+ for(strend = str; *strend; strend++)
+ ;
--strend;
if(*str=='#') {
i = m68k_reg_parse(&str);
- /* is a register, is exactly a register, and is followed by '@' */
+ if (i!=FAIL) {
+ if(*str=='/' || *str=='-') {
+ /* "Rm-Rn/Ro-Rp" Register list for MOVEM instruction */
+ opP->mode=REGLST;
+ return get_regs(i,str,opP);
+ }
+ if(*str=='\0') {
+ opP->reg=i;
+ /* "Rn" Register Direct mode */
+ if(i>=DATA+0 && i<=DATA+7)
+ opP->mode=DREG;
+ else if(i>=ADDR+0 && i<=ADDR+7)
+ opP->mode=AREG;
+ else
+ opP->mode=MSCR;
+ return OK;
+ }
+ }
- if((i==FAIL || *str!='\0') && *str!='@') {
+ if (*str!='@') {
char *stmp;
- if(i!=FAIL && (*str=='/' || *str=='-')) {
- opP->mode=REGLST;
- return(get_regs(i,str,opP));
- }
- if ((stmp=strchr(str,'@')) != '\0') {
+ if ((stmp=strchr(str,'@')) != 0) {
opP->con1=add_exp(str,stmp-1);
if(stmp==strend) {
opP->mode=AINDX;
}
return(OK);
} /* if there's an '@' */
- opP->mode = ABSL;
- opP->con1 = add_exp(str,strend);
- return(OK);
- } /* not a register, not exactly a register, or no '@' */
- opP->reg=i;
+#ifndef MIT_SYNTAX_ONLY
+ /* The operand has no '@'. Try to parse it using
+ Motorola syntax. */
+ /* Logic of the parsing switch(*str):
+ case opP->mode =
+ ---- -----------
+ #anything IMMED 1
+ REG AREG or DREG or MSCR 3 or 2 or 13
+ REG- or REG/ REGLST 14
+ (REG) AINDR 4
+ (REG)+ AINC 6
+ (REG,INDX) AINDX 8
+ (EXPR,REG) AOFF 7
+ (EXPR,REG,INDX) AINDX 8
+ -(REG) ADEC 5
+ EXP2(REG) AOFF 7
+ EXP2(REG,INDX) AINDX 8
+ EXP2 ABSL 12
+
+ REG means truth(m68k_reg_parse(&str))
+ INDX means truth(try_moto_index(&str,opP))
+ EXPR means not REG
+ EXP2 means not REG and not '(' and not '-('
+ */
+
+ if(*str=='(') {
+ str++;
+ i=m68k_reg_parse(&str);
+ if((i<ADDR+0 || i>ADDR+7)
+ && (i<DATA+0 || i>DATA+7
+ || *str != ')' || str[1] != '0')
+ && i!=PC && i!=ZPC && i!=FAIL) {
+ /* Can't indirect off non address regs */
+ opP->error="Invalid indirect register";
+ return FAIL;
+ }
+ if(i!=FAIL) {
+ opP->reg=i;
+ if(*str==')') {
+ str++;
+ if(*str=='\0') {
+ /* "(An)" Address Register Indirect mode
+ or "(Dn)" for cas2. */
+ if (i>=DATA+0 && i<=DATA+7)
+ opP->mode=DINDR;
+ else
+ opP->mode=AINDR;
+ return OK;
+ }
+ if(*str=='+') {
+ if(str[1]=='\0') {
+ /* "(An)+" Register Indirect w Postincrement */
+ opP->mode=AINC;
+ return OK;
+ }
+ }
+ opP->error="Junk after indirect";
+ return FAIL;
+ }
+ if(*str==',') {
+ str++;
+ i=try_moto_index(&str,opP);
+ if(i==FAIL) return FAIL;
+ /* "(An,Rn)" Register Indirect with Index mode*/
+ opP->mode=AINDX;
+ return OK;
+ }
+ else {
+ opP->error="Bad indirect syntax";
+ return FAIL;
+ }
+ }
+ else {
+ /* "(EXPR,..." , a displacement */
+ char *stmp;
+ char *index();
+
+ if(stmp=index(str,',')) {
+ opP->con1=add_exp(str,stmp-1);
+ str=stmp;
+ SKIP_WHITE();
+ i=m68k_reg_parse(&str);
+ if((i<ADDR+0 || i>ADDR+7) && i!=PC && i!=ZPC) {
+ /* Can't indirect off non address regs */
+ opP->error="Invalid indirect register";
+ return FAIL;
+ }
+ if(i!=FAIL) {
+ opP->reg=i;
+ if(*str==')') {
+ /* "(d,An)" Register Indirect w Displacement */
+ opP->mode=AOFF;
+ return OK;
+ }
+ if(*str==',') {
+ str++;
+ i=try_moto_index(&str,opP);
+ if(i==FAIL) return FAIL;
+ /* "(d,An,Rn)" Register Indirect with Index */
+ opP->mode=AINDX;
+ return OK;
+ }
+ else {
+ opP->error="Bad indirect syntax";
+ return FAIL;
+ }
+ }
+ else {
+ opP->error="Invalid register";
+ return FAIL;
+ }
+ }
+ else {
+ opP->mode = ABSL;
+ opP->con1 = add_exp(str-1,strend);
+ return OK;
+ }
+ }
+ }
- if (*str=='\0') {
- if(i>=DATA+0 && i<=DATA+7)
- opP->mode=DREG;
- else if(i>=ADDR+0 && i<=ADDR+7)
- opP->mode=AREG;
- else
- opP->mode=MSCR;
+ if(*str=='-') {
+ if(str[1]=='(') {
+ str = str+2;
+ i=m68k_reg_parse(&str);
+ if((i<ADDR+0 || i>ADDR+7) && i!=PC && i!=ZPC && i!=FAIL) {
+ /* Can't indirect off non address regs */
+ opP->error="Invalid indirect register";
+ return FAIL;
+ }
+ if(i!=FAIL) {
+ opP->reg=i;
+ if(*str==')') {
+ str++;
+ if(*str=='\0') {
+ /* "-(An)" Register Indirect with Predecrement */
+ opP->mode=ADEC;
+ return OK;
+ }
+ opP->error="Junk after indirect";
+ return FAIL;
+ }
+ opP->error="Bad indirect syntax";
+ return FAIL;
+ }
+ opP->mode = ABSL;
+ opP->con1 = add_exp(str-2,strend);
+ return OK;
+ }
+ /* if '-' but not "-(', do nothing */
+ }
+
+ /* whether *str=='-' or not */
+ {
+ /* "EXP2" or "EXP2(REG..." */
+ char *stmp;
+ char *index();
+ if(stmp=index(str,'(')) {
+ char *ostr=str;
+
+ opP->con1=add_exp(str,stmp-1);
+ str=stmp+1;
+ i=m68k_reg_parse(&str);
+ if((i<ADDR+0 || i>ADDR+7) && i!=PC
+ && i!=ZPC && i!=FAIL) {
+ /* Can't indirect off non address regs */
+ opP->error="Invalid indirect register";
+ return FAIL;
+ }
+ if(i!=FAIL) {
+ opP->reg=i;
+ if(*str==')') {
+ /* "d(An)" Register Indirect w Displacement */
+ opP->mode=AOFF;
+ return OK;
+ }
+ if(*str==',') {
+ str++;
+ i=try_moto_index(&str,opP);
+ if(i==FAIL) return FAIL;
+ /* "d(An,Rn)" Register Indirect with Index */
+ opP->mode=AINDX;
+ return OK;
+ }
+ else {
+ opP->error="Bad indirect syntax";
+ return FAIL;
+ }
+ }
+ else {
+ opP->mode = ABSL;
+ opP->con1 = add_exp(ostr,strend);
+ return OK;
+ }
+ }
+ else {
+ /* "EXP2" Absolute */
+ opP->mode=ABSL;
+ opP->isiz=0;
+ if(strend[-1]=='.' || strend[-1]==':') {
+ /* mode ==foo.[wl] */
+ switch(*strend) {
+ case 'w':
+ case 'W':
+ opP->isiz=2;
+ strend-=2;
+ break;
+ case 'l':
+ case 'L':
+ opP->isiz=3;
+ strend-=2;
+ break;
+ }
+ }
+ opP->con1=add_exp(str,strend);
+ return OK;
+ }
+ }
+ /*NOTREACHED*/
+#else /* defined (MIT_SYNTAX_ONLY) */
+ opP->mode=ABSL;
+ opP->con1=add_exp(str,strend);
return OK;
- }
+#endif /* defined (MIT_SYNTAX_ONLY) */
+ }
+
+ opP->reg=i;
- if((i<ADDR+0 || i>ADDR+7) && i!=PC && i!=ZPC && i!=FAIL) { /* Can't indirect off non address regs */
+ /* Can't indirect off non address regs, but Dx@ is OK for cas2 */
+ if((i<ADDR+0 || i>ADDR+7) && i!=PC && i!=ZPC && i!=FAIL
+ && (str[1] != '\0' || i<DATA+0 || i>DATA+7)) {
opP->error="Invalid indirect register";
return FAIL;
}
str++;
switch(*str) {
case '\0':
- opP->mode=AINDR;
+ if (i<DATA+0 || i>DATA+7)
+ opP->mode=AINDR;
+ else
+ opP->mode=DINDR;
return OK;
case '-':
opP->mode=ADEC;
return(OK);
} /* m68k_ip_op() */
-/*
- *
- * try_index := data_or_address_register + ')' + SKIP_W
- * | data_or_address_register + ':' + SKIP_W + size_spec + SKIP_W + multiplier + ')' + SKIP_W
- *
- * multiplier := <empty>
- * | ':' + multiplier_number
- * ;
- *
- * multiplier_number := '1' | '2' | '4' | '8' ;
- *
- * size_spec := 'l' | 'L' | 'w' | 'W' ;
- *
- * SKIP_W := <empty> | ' ' ;
- *
- */
-static int try_index(s,opP)
-char **s;
-struct m68k_op *opP;
+#ifdef M68KCOFF
+
+short tc_coff_fix2rtype(fixP)
+fixS *fixP;
{
- register int i;
- char *ss;
-#define SKIP_W() { ss++; if (*ss==' ') ss++;}
+ return (fixP->fx_pcrel ?
+ (fixP->fx_size == 1 ? R_PCRBYTE :
+ fixP->fx_size == 2 ? R_PCRWORD :
+ R_PCRLONG):
+ (fixP->fx_size == 1 ? R_RELBYTE :
+ fixP->fx_size == 2 ? R_RELWORD :
+ R_RELLONG));
- ss= *s;
- /* SKIP_W(); */
- i=m68k_reg_parse(&ss);
- if(!(i>=DATA+0 && i<=ADDR+7)) { /* if i is not DATA or ADDR reg */
- *s=ss;
- return FAIL;
- }
- opP->ireg=i;
- /* SKIP_W(); */
- if(*ss==')') {
- opP->isiz=0;
- opP->imul=1;
- SKIP_W();
- *s=ss;
- return OK;
- }
- if(*ss!=':') {
- opP->error="Missing : in index register";
- *s=ss;
- return FAIL;
- }
- SKIP_W();
- switch(*ss) {
- case 'w':
- case 'W':
- opP->isiz=2;
- break;
- case 'l':
- case 'L':
- opP->isiz=3;
- break;
- default:
- opP->error="Index register size spec not :w or :l";
- *s=ss;
- return FAIL;
- }
- SKIP_W();
- if(*ss==':') {
- SKIP_W();
- switch(*ss) {
- case '1':
- case '2':
- case '4':
- case '8':
- if (cpu_of_arch(current_architecture) < m68020) {
- opP->error="no index scaling in pre-68020's";
- *s=ss;
- return FAIL;
- }
- opP->imul= *ss-'0';
- break;
- default:
- opP->error="index multiplier not 1, 2, 4 or 8";
- *s=ss;
- return FAIL;
- }
- SKIP_W();
- } else opP->imul=1;
- if(*ss!=')') {
- opP->error="Missing )";
- *s=ss;
- return FAIL;
- }
- SKIP_W();
- *s=ss;
- return OK;
-} /* try_index() */
+
+}
+
+#endif
#ifdef TEST1 /* TEST1 tests m68k_ip_op(), which parses operands */
main()
register struct m68k_incant *opcode;
register char *s;
register int tmpreg = 0, baseo = 0, outro = 0, nextword;
+ char *pdot, *pdotmove;
int siz1, siz2;
char c;
int losing;
/* Scan up to end of operation-code, which MUST end in end-of-string
or exactly 1 space. */
- for (p = instring; *p != '\0'; p++)
+ pdot = 0;
+ for (p = instring; *p != '\0'; p++) {
if (*p == ' ')
break;
-
+ if (*p == '.')
+ pdot = p;
+ }
if (p == instring) {
the_ins.error = "No operator";
/* p now points to the end of the opcode name, probably whitespace.
make sure the name is null terminated by clobbering the whitespace,
- look it up in the hash table, then fix it back. */
+ look it up in the hash table, then fix it back.
+ Remove a dot, first, since the opcode tables have none. */
+ if (pdot != NULL) {
+ for (pdotmove=pdot; pdotmove<p; pdotmove++)
+ *pdotmove=pdotmove[1];
+ p--;
+ }
+
c = *p;
*p = '\0';
opcode = (struct m68k_incant *)hash_find (op_hash, instring);
*p = c;
+ if (pdot != NULL) {
+ for (pdotmove=p; pdotmove>pdot; pdotmove--)
+ *pdotmove=pdotmove[-1];
+ *pdot='.';
+ ++p;
+ }
+
if (opcode == NULL) {
the_ins.error = "Unknown operator";
the_ins.opcode[0] = NULL;
/* found a legitimate opcode, start matching operands */
while (*p == ' ') ++p;
+
+ if (opcode->m_operands == 0) {
+ char *old = input_line_pointer;
+ *old = '\n';
+ input_line_pointer = p;
+ /* Ahh - it's a motorola style psuedo op */
+ mote_pseudo_table[opcode->m_opnum].poc_handler
+ ( mote_pseudo_table[opcode->m_opnum].poc_val);
+ input_line_pointer = old;
+ *old = 0;
+
+ return;
+ }
+
for(opP = &the_ins.operands[0]; *p; opP++) {
p = crack_operand(p, opP);
losing++;
break;
+ case '`':
+ switch (opP->mode) {
+ case MSCR: case IMMED: case DREG: case AREG:
+ case AINC: case REGLST: case AINDR:
+ losing++;
+ }
+ break;
+
case '#':
if(opP->mode!=IMMED)
losing++;
losing++;
break;
+ case '3':
+ if (opP->mode != MSCR || (opP->reg != TT0 && opP->reg != TT1))
+ losing++;
+ break;
+
case 'A':
if(opP->mode!=AREG)
losing++;
losing++;
break;
+ case 'r':
+ if (opP->mode!=AINDR && opP->mode!=DINDR)
+ losing++;
+ break;
+
case 's':
if(opP->mode!=MSCR || !(opP->reg==FPI || opP->reg==FPS || opP->reg==FPC))
losing++;
losing++;
break;
+ case 't':
+ if (opP->mode != IMMED)
+ losing++;
+ else
+ {
+ long t = get_num (opP->con1, 80);
+ if (t < 0 || t > 7 || isvar (opP->con1))
+ losing++;
+ }
+ break;
+
case 'U':
if(opP->mode!=MSCR || opP->reg!=USP)
losing++;
/* JF these are out of order. We could put them
in order if we were willing to put up with
- bunches of #ifdef m68851s in the code */
+ bunches of #ifdef m68851s in the code.
+
+ Don't forget that you need these operands
+ to use 68030 MMU instructions. */
#ifndef NO_68851
/* Memory addressing mode used by pflushr */
case '|':
break;
case 'P':
- if (opP->mode != MSCR || (opP->reg != TC && opP->reg != CAL &&
- opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
+ if (opP->mode != MSCR
+ || (opP->reg != TC && opP->reg != CAL
+ && opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
losing++;
break;
break;
case 'W':
- if (opP->mode != MSCR || (opP->reg != DRP && opP->reg != SRP &&
- opP->reg != CRP))
+ if (opP->mode != MSCR
+ || (opP->reg != DRP && opP->reg != SRP
+ && opP->reg != CRP))
losing++;
break;
break;
default:
- as_fatal("Internal error: Operand mode %c unknown in line %s of file \"%s\"",
+ as_fatal("Internal error: Operand mode %c unknown in line %d of file \"%s\"",
*s, __LINE__, __FILE__);
} /* switch on type of operand */
opcode = opcode->m_next;
if (!opcode) {
- if (ok_arch)
+ if (ok_arch
+ && !(ok_arch & current_architecture))
{
char buf[200], *cp;
int len;
switch (ok_arch)
{
case mfloat:
- strcpy (cp, "fpu");
+ strcpy (cp, "fpu (68040 or 68881/68882)");
break;
case mmmu:
- strcpy (cp, "mmu");
+ strcpy (cp, "mmu (68030 or 68851)");
break;
case m68020up:
strcpy (cp, "68020 or higher");
{
int got_one = 0, idx;
const static struct {
- enum m68k_architecture arch;
+ int arch;
const char *name;
} archs[] = {
m68000, "68000",
m68020, "68020",
m68030, "68030",
m68040, "68040",
+ cpu32, "cpu32",
m68881, "68881",
m68851, "68851",
};
case '$':
case '?':
case '/':
+ case '`':
#ifndef NO_68851
case '|':
#endif
break;
} /* Its BIG */
if(offs(opP->con1)>0) {
- as_warn("Bignum assumed to be binary bit-pattern");
if(offs(opP->con1)>baseo) {
as_warn("Bignum too big for %c format; truncated",s[1]);
offs(opP->con1)=baseo;
break;
} else {
addword(0x0170);
- add_fix('l',opP->con1,1);
+ add_fix('l',opP->con1,0);
}
} else
addword(0x0170);
break;
}
break;
+ case DINDR:
+ as_bad("invalid indirect register");
+ break;
case MSCR:
default:
as_bad("unknown/incorrect operand");
&& (the_ins.opcode[0] <= 0x6f00)) {
add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
} else {
- add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
+ add_frag(adds(opP->con1),offs(opP->con1),TAB(ABRANCH,SZ_UNDEF));
}
break;
case 'w':
break;
case 'R':
+ case 'r':
/* This depends on the fact that ADDR registers are
eight more than their corresponding DATA regs, so
the result will have the ADDR_REG bit set */
know(opP->reg == PCSR);
break;
#endif /* m68851 */
- case '_':
+ case '3':
+ switch (opP->reg)
+ {
+ case TT0:
+ tmpreg = 2;
+ break;
+ case TT1:
+ tmpreg = 3;
+ break;
+ default:
+ as_fatal ("failed sanity check");
+ }
+ install_operand (s[1], tmpreg);
+ break;
+ case 't':
+ tmpreg = get_num (opP->con1, 20);
+ install_operand (s[1], tmpreg);
+ break;
+ case '_': /* used only for move16 absolute 32-bit address */
tmpreg=get_num(opP->con1,80);
- install_operand(s[1], tmpreg);
+ addword (tmpreg >> 16);
+ addword (tmpreg & 0xFFFF);
break;
default:
- as_fatal("Internal error: Operand type %c unknown in line %s of file \"%s\"", s[0], __LINE__, __FILE__);
+ as_fatal("Internal error: Operand type %c unknown in line %d of file \"%s\"",
+ s[0], __LINE__, __FILE__);
}
}
+
/* By the time whe get here (FINALLY) the_ins contains the complete
instruction, ready to be emitted. . . */
} /* m68k_ip() */
symbol_table_insert(symbol_new(buf, SEG_REGISTER, regnum, &zero_address_frag));
}
-static struct {
+static const struct {
char *name;
int number;
-} init_table[] =
-{
+} init_table[] = {
"d0", DATA0,
"d1", DATA1,
"d2", DATA2,
"srp", SRP,
"urp", URP,
-#ifndef NO_68851
"ac", AC,
"bc", BC,
"cal", CAL,
"bac5", BAC5,
"bac6", BAC6,
"bac7", BAC7,
-#endif
"ic", IC,
"dc", DC,
"nc", NC,
+ "tt0", TT0,
+ "tt1", TT1,
+ /* 68ec030 versions of same */
+ "ac0", TT0,
+ "ac1", TT1,
+ /* 68ec030 access control unit, identical to 030 MMU status reg */
+ "acusr", PSR,
+
0,
};
{
int i;
for (i = 0; init_table[i].name; i++)
- {
insert_reg(init_table[i].name, init_table[i].number);
- }
}
+static int no_68851, no_68881;
void
md_assemble(str)
int m,n = 0;
char *to_beg_P;
int shorts_this_frag;
+ static int done_first_time;
+ if (!done_first_time)
+ {
+ done_first_time = 1;
- if (current_architecture == 0)
- current_architecture = (m68020
-#ifndef NO_68881
- | m68881
-#endif
-#ifndef NO_68851
- | m68851
+ if (cpu_of_arch (current_architecture) == 0)
+ {
+ int cpu_type;
+
+#ifndef TARGET_CPU
+ cpu_type = m68020;
+#else
+ if (strcmp (TARGET_CPU, "m68000") == 0)
+ cpu_type = m68000;
+ else if (strcmp (TARGET_CPU, "m68010") == 0)
+ cpu_type = m68010;
+ else if (strcmp (TARGET_CPU, "m68020") == 0
+ || strcmp (TARGET_CPU, "m68k") == 0)
+ cpu_type = m68020;
+ else if (strcmp (TARGET_CPU, "m68030") == 0)
+ cpu_type = m68030;
+ else if (strcmp (TARGET_CPU, "m68040") == 0)
+ cpu_type = m68040;
+ else if (strcmp (TARGET_CPU, "cpu32") == 0)
+ cpu_type = cpu32;
+ else
+ cpu_type = m68020;
#endif
- );
- /* If only float and mmu were specified, default cpu. */
- else if (cpu_of_arch (current_architecture) == 0)
- current_architecture |= m68020;
+
+ current_architecture |= cpu_type;
+ }
+ if (current_architecture & m68881)
+ {
+ if (current_architecture & m68000)
+ as_bad ("incompatible processors 68000 and 68881/2 specified");
+ if (current_architecture & m68010)
+ as_bad ("incompatible processors 68010 and 68881/2 specified");
+ if (current_architecture & m68040)
+ as_bad ("incompatible processors 68040 and 68881/2 specified");
+ }
+ /* What other incompatibilities ought we to check for? */
+
+ /* Toss in some default assumptions about coprocessors. */
+ if (!no_68881
+ && (cpu_of_arch (current_architecture)
+ /* Can CPU32 have a 68881 coprocessor?? */
+ & (m68020 | m68030 | cpu32)))
+ {
+ current_architecture |= m68881;
+ }
+ if (!no_68851
+ && (cpu_of_arch (current_architecture) & m68020up) != 0)
+ {
+ current_architecture |= m68851;
+ }
+ if (no_68881 && (current_architecture & m68881))
+ as_bad ("options for 68881 and no-68881 both given");
+ if (no_68851 && (current_architecture & m68851))
+ as_bad ("options for 68851 and no-68851 both given");
+ done_first_time = 1;
+ }
memset((char *)(&the_ins), '\0', sizeof(the_ins)); /* JF for paranoia sake */
m68k_ip(str);
-
-
void
md_begin()
{
retval = hash_insert (op_hash, ins->name,(char *)hack);
/* Didn't his mommy tell him about null pointers? */
if(retval && *retval)
- as_fatal("Internal Error: Can't hash %s: %s",ins->name,retval);
+ as_bad("Internal Error: Can't hash %s: %s",ins->name,retval);
}
for (i = 0; i < sizeof(mklower_table) ; i++)
alt_notend_table[REGISTER_PREFIX] = 1;
#endif
+#ifndef MIT_SYNTAX_ONLY
+ /* Insert pseudo ops, these have to go into the opcode table since
+ gas expects pseudo ops to start with a dot */
+ {
+ int n = 0;
+ while (mote_pseudo_table[n].poc_name)
+ {
+ hack=(struct m68k_incant *)
+ obstack_alloc(&robyn,sizeof(struct m68k_incant));
+ hash_insert(op_hash,
+ mote_pseudo_table[n].poc_name, (char *)hack);
+ hack->m_operands = 0;
+ hack->m_opnum = n;
+ n++;
+ }
+ }
+#endif
+
init_regtable();
}
fixS *fixP;
long val;
{
+#ifdef IBM_COMPILER_SUX
+ /* This is unnecessary but it convinces the native rs6000
+ compiler to generate the code we want. */
+ char *buf = fixP->fx_frag->fr_literal;
+ buf += fixP->fx_where;
+#else /* IBM_COMPILER_SUX */
char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+#endif /* IBM_COMPILER_SUX */
switch(fixP->fx_size) {
case 1:
switch(fragP->fr_subtype) {
case TAB(BCC68000,BYTE):
- case TAB(BRANCH,BYTE):
+ case TAB(ABRANCH,BYTE):
know(issbyte(disp));
if(disp==0)
as_bad("short branch with zero offset: use :w");
ext=2;
break;
case TAB(BCC68000,SHORT):
- case TAB(BRANCH,SHORT):
+ case TAB(ABRANCH,SHORT):
know(issword(disp));
fragP->fr_opcode[1]=0x00;
ext=2;
break;
- case TAB(BRANCH,LONG):
+ case TAB(ABRANCH,LONG):
if (cpu_of_arch(current_architecture) < m68020) {
if (fragP->fr_opcode[0]==0x61) {
fragP->fr_opcode[0]= 0x4E;
/* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
switch (fragP->fr_subtype) {
- case TAB(BRANCH,SZ_UNDEF): {
+ case TAB(ABRANCH,SZ_UNDEF): {
if((fragP->fr_symbol != NULL) /* Not absolute */
&& S_GET_SEGMENT(fragP->fr_symbol) == segment) {
fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE);
}
break;
- } /* case TAB(BRANCH,SZ_UNDEF) */
+ } /* case TAB(ABRANCH,SZ_UNDEF) */
case TAB(FBRANCH,SZ_UNDEF): {
if(S_GET_SEGMENT(fragP->fr_symbol) == segment || flagseen['l']) {
/* now that SZ_UNDEF are taken care of, check others */
switch (fragP->fr_subtype) {
case TAB(BCC68000,BYTE):
- case TAB(BRANCH,BYTE):
+ case TAB(ABRANCH,BYTE):
/* We can't do a short jump to the next instruction,
so we force word mode. */
if (fragP->fr_symbol && S_GET_VALUE(fragP->fr_symbol)==0 &&
}
exp->e_siz=0;
- if(/* ok!=80 && */exp->e_end[-1]==':' && (exp->e_end-exp->e_beg)>=2) {
+ if(/* ok!=80 && */ (exp->e_end[-1]==':' || exp->e_end[-1]=='.')
+ && (exp->e_end-exp->e_beg)>=2) {
switch(exp->e_end[0]) {
case 's':
case 'S':
case 'b':
case 'B':
exp->e_siz=1;
+ exp->e_end-=2;
break;
case 'w':
case 'W':
exp->e_siz=2;
+ exp->e_end-=2;
break;
case 'l':
case 'L':
exp->e_siz=3;
+ exp->e_end-=2;
break;
default:
- as_bad("Unknown size for expression \"%c\"",exp->e_end[0]);
+ if (exp->e_end[-1] == ':')
+ as_bad("Unknown size for expression \"%c\"",exp->e_end[0]);
+ break;
}
- exp->e_end-=2;
}
c_save=exp->e_end[1];
exp->e_end[1]='\0';
break;
}
break;
- case SEG_TEXT:
- case SEG_DATA:
- case SEG_BSS:
- case SEG_UNKNOWN:
- case SEG_DIFFERENCE:
- if(ok>=10 && ok<=70) {
+ case SEG_BIG:
+ if (offs (exp) < 0 /* flonum */
+ && (ok == 80 /* no bignums */
+ || (ok > 10 /* small-int ranges including 0 ok */
+ /* If we have a flonum zero, a zero integer should
+ do as well (e.g., in moveq). */
+ && generic_floating_point_number.exponent == 0
+ && generic_floating_point_number.low[0] == 0)))
+ {
+ /* HACK! Turn it into a long */
+ LITTLENUM_TYPE words[6];
+
+ gen_to_words(words,2,8L);/* These numbers are magic! */
+ seg(exp)=SEG_ABSOLUTE;
+ adds(exp)=0;
+ subs(exp)=0;
+ offs(exp)=words[1]|(words[0]<<16);
+ }
+ else if(ok!=0) {
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
}
break;
- case SEG_BIG:
- if(ok==80 && offs(exp)<0) { /* HACK! Turn it into a long */
- LITTLENUM_TYPE words[6];
-
- gen_to_words(words,2,8L);/* These numbers are magic! */
- seg(exp)=SEG_ABSOLUTE;
- adds(exp)=0;
- subs(exp)=0;
- offs(exp)=words[1]|(words[0]<<16);
- } else if(ok!=0) {
+ default:
+ case SEG_TEXT:
+ case SEG_DATA:
+ case SEG_BSS:
+ case SEG_UNKNOWN:
+ case SEG_DIFFERENCE:
+ if(ok>=10 && ok<=70) {
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
}
break;
- default:
- as_fatal("failed sanity check.");
+
+
}
if(input_line_pointer!=exp->e_end+1)
as_bad("Ignoring junk after expression");
* errors. More than one may be specified. The default is
* -m68020 -m68851 -m68881. Note that -m68008 is a synonym
* for -m68000, and -m68882 is a synonym for -m68881.
+ * -[A]m[c]no-68851, -[A]m[c]no-68881
+ * Don't accept 688?1 instructions. (The "c" is kind of silly,
+ * so don't use or document it, but that's the way the parsing
+ * works).
*
* MAYBE_FLOAT_TOO is defined below so that specifying a processor type
* (e.g. m68020) also requests that float instructions be included. This
* of that funny floaty stuff going on. FIXME-later.
*/
#ifndef MAYBE_FLOAT_TOO
-#define MAYBE_FLOAT_TOO m68881
+#define MAYBE_FLOAT_TOO /* m68881 */ 0 /* this is handled later */
#endif
int md_parse_option(argP,cntP,vecP)
} else if (!strcmp(*argP, "68882")) {
current_architecture |= m68882;
-
#endif /* NO_68881 */
+ /* Even if we aren't configured to support the processor,
+ it should still be possible to assert that the user
+ doesn't have it... */
+ } else if (!strcmp (*argP, "no-68881")
+ || !strcmp (*argP, "no-68882")) {
+ no_68881 = 1;
#ifndef NO_68851
} else if (!strcmp(*argP,"68851")) {
current_architecture |= m68851;
-
#endif /* NO_68851 */
+ } else if (!strcmp (*argP, "no-68851")) {
+ no_68851 = 1;
+ } else if (!strcmp (*argP, "pu32")) { /* "-mcpu32" */
+ current_architecture |= cpu32;
} else {
as_warn("Unknown architecture, \"%s\". option ignored", *argP);
} /* switch on architecture */
return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address);
}
+void
+tc_coff_symbol_emit_hook ()
+{
+}
+
+int
+tc_coff_sizemachdep(frag)
+fragS *frag;
+{
+ switch (frag->fr_subtype & 0x3)
+ {
+ case BYTE: return 1;
+ case SHORT: return 2;
+ case LONG: return 4;
+ default: abort();
+ }
+
+}
/*
* Local Variables:
* comment-column: 0
*/
/* end of tc-m68k.c */
+