#undef CHECK_WORD_IMMEDIATES
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "m68k-opcode.h"
#include "as.h"
#include "obstack.h"
#include "struc-symbol.h"
#include "flonum.h"
#include "expr.h"
#include "hash.h"
#include "frags.h"
#include "fixes.h"
#include "read.h"
#include "md.h"
#ifndef NeXT_MOD
#include "m68k.h"
#endif
#include "xmalloc.h"
#include "sections.h"
#include "messages.h"
#include "atof-ieee.h"
#include "input-scrub.h"
#include "symbols.h"
const cpu_type_t md_cputype = CPU_TYPE_MC680x0;
cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_MC680x0_ALL;
const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX;
const char md_comment_chars[] = "|";
const char md_line_comment_chars[] = "#";
const char md_EXP_CHARS[] = "eE";
const char md_FLT_CHARS[] = "rRsSfFdDxXeEpP";
static struct obstack robyn;
#define TAB(x,y) (((x)<<2)+(y))
#define TABTYPE(xy) ((xy) >> 2)
#define BRANCH 1
#define FBRANCH 2
#define PCREL 3
#define BCC68000 4
#define DBCC 5
#define BYTE 0
#define SHORT 1
#define LONG 2
#define SZ_UNDEF 3
const
relax_typeS
md_relax_table[] = {
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ (127), (-128), 0, TAB(BRANCH,SHORT)},
{ (32767), (-32768), 2, TAB(BRANCH,LONG) },
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ (32767), (-32768), 2, TAB(FBRANCH,LONG)},
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ (32767), (-32768), 2, TAB(PCREL,LONG)},
{ 0, 0, 4, 0 },
{ 1, 1, 0, 0 },
{ (127), (-128), 0, TAB(BCC68000,SHORT)},
{ (32767), (-32768), 2, TAB(BCC68000,LONG) },
{ 0, 0, 6, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ (32767), (-32768), 2, TAB(DBCC,LONG) },
{ 0, 0, 10, 0 },
{ 1, 1, 0, 0 },
};
static void s_even(
uintptr_t value);
static void s_proc(
uintptr_t value);
const pseudo_typeS md_pseudo_table[] = {
{ "float", float_cons, 'f' },
{ "int", cons, 4 },
{ "word", cons, 2 },
{ "quad", big_cons, 8 },
{ "octa", big_cons, 16 },
{ "even", s_even, 0 },
{ "skip", s_space, 0 },
{ "proc", s_proc, 0 },
{ 0, 0, 0 }
};
#define issbyte(x) ((x)>=-128 && (x)<=127)
#define isubyte(x) ((x)>=0 && (x)<=255)
#define issword(x) ((x)>=-32768 && (x)<=32767)
#define isuword(x) ((x)>=0 && (x)<=65535)
#define isbyte(x) ((x)>=-128 && (x)<=255)
#define isword(x) ((x)>=-32768 && (x)<=65535)
#define islong(x) (1)
#define IMMED 1
#define DREG 2
#define AREG 3
#define AINDR 4
#define ADEC 5
#define AINC 6
#define AOFF 7
#define AINDX 8
#define APODX 9
#define AMIND 10
#define APRDX 11
#define ABSL 12
#define MSCR 13
#define REGLST 14
#define FAIL 0
#define OK 1
#define DATA 1
#define ADDR (DATA+8)
#define FPREG (ADDR+8)
#define COPNUM (FPREG+8)
#undef PC
#define PC (COPNUM+8)
#define ZPC (PC+1)
#define SR (ZPC+1)
#define CCR (SR+1)
#define FPI (CCR+1)
#define FPS (FPI+1)
#define FPC (FPS+1)
#define USP (FPC+1)
#define ISP (USP+1)
#define SFC (ISP+1)
#define DFC (SFC+1)
#define CACR (DFC+1)
#define VBR (CACR+1)
#define CAAR (VBR+1)
#define MSP (CAAR+1)
#ifdef BUILTIN_MMUS
#define ITT0 (MSP+1)
#define ITT1 (ITT0+1)
#define DTT0 (ITT1+1)
#define DTT1 (DTT0+1)
#define URP (DTT1+1)
#define MMUSR (URP+1)
#define TC (MMUSR+1)
#define SRP (TC+1)
#define CRP (SRP+1)
#define TT0 (CRP+1)
#define TT1 (TT0+1)
#define IC (TT1+1)
#define DC (IC+1)
#define BC (DC+1)
#endif
#ifdef m68851
#define TC (MSP+1)
#define DRP (TC+1)
#define SRP (DRP+1)
#define CRP (SRP+1)
#define CAL (CRP+1)
#define VAL (CAL+1)
#define SCC (VAL+1)
#define AC (SCC+1)
#define BAD (AC+1)
#define BAC (BAD+8)
#define PSR (BAC+8)
#define PCSR (PSR+1)
#endif
#undef SP
#define SP ADDR+7
static char mklower_table[256];
#define mklower(c) (mklower_table[(unsigned char)(c)])
static char notend_table[256];
static char alt_notend_table[256];
#define notend(s) ( !(notend_table[(unsigned char)(*s)] || (*s==':' &&\
alt_notend_table[(unsigned char)(s[1])])))
#if 0
#define mklower(c) (isupper(c) ? tolower(c) : c)
#endif
struct m68k_exp {
char *e_beg;
char *e_end;
expressionS e_exp;
short e_siz;
};
struct m68k_op {
char *error;
int mode;
uint32_t reg;
struct m68k_exp *con1;
int ireg;
int isiz;
int imul;
struct m68k_exp *con2;
};
struct m68_it {
char *error;
char *args;
int numargs;
#ifdef NeXT_MOD
char *cpus;
#endif
int numo;
short opcode[11];
struct m68k_op operands[6];
int nexp;
struct m68k_exp exprs[4];
int nfrag;
struct {
int fragoff;
symbolS *fadd;
int32_t foff;
int fragty;
} fragb[4];
int nrel;
struct {
int n;
symbolS *add,
*sub;
int32_t off;
char wid;
char pcrel;
} reloc[5];
};
static struct m68_it the_ins;
#define addword(w) the_ins.opcode[the_ins.numo++]=(w)
#define insop(w) {int z;\
for(z=the_ins.numo;z>opcode->m_codenum;--z)\
the_ins.opcode[z]=the_ins.opcode[z-1];\
for(z=0;z<the_ins.nrel;z++)\
the_ins.reloc[z].n+=2;\
the_ins.opcode[opcode->m_codenum]=(w);\
the_ins.numo++;\
}
#define add_exp(beg,end) (\
the_ins.exprs[the_ins.nexp].e_beg=(beg),\
the_ins.exprs[the_ins.nexp].e_end=(end),\
&the_ins.exprs[the_ins.nexp++]\
)
#define add_fix(width,exp,pc_rel) {\
the_ins.reloc[the_ins.nrel].n= ((width)=='B') ? (the_ins.numo*2-1) : \
(((width)=='b') ? ((the_ins.numo-1)*2) : (the_ins.numo*2));\
the_ins.reloc[the_ins.nrel].add=adds((exp));\
the_ins.reloc[the_ins.nrel].sub=subs((exp));\
the_ins.reloc[the_ins.nrel].off=offs((exp));\
the_ins.reloc[the_ins.nrel].wid=(width);\
the_ins.reloc[the_ins.nrel++].pcrel=(pc_rel);\
}
#define add_frag(add,off,type) {\
the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\
the_ins.fragb[the_ins.nfrag].fadd=(add);\
the_ins.fragb[the_ins.nfrag].foff=(off);\
the_ins.fragb[the_ins.nfrag++].fragty=(type);\
}
#define isvar(exp) ((exp) && (adds(exp) || subs(exp)))
#define seg(exp) ((exp)->e_exp.X_seg)
#define adds(exp) ((exp)->e_exp.X_add_symbol)
#define subs(exp) ((exp)->e_exp.X_subtract_symbol)
#define offs(exp) ((exp)->e_exp.X_add_number)
struct m68_incant {
char *m_operands;
uint32_t m_opcode;
short m_opnum;
short m_codenum;
#ifdef NeXT_MOD
char *m_cpus;
#endif
struct m68_incant *m_next;
};
#define getone(x) ((((x)->m_opcode)>>16)&0xffff)
#define gettwo(x) (((x)->m_opcode)&0xffff)
static int m68k_reg_parse(
char **ccp);
static int m68k_ip_op(
char *str,
struct m68k_op *opP);
static int try_index(
char **s,
struct m68k_op *opP);
static void m68_ip(
char *instring);
static int get_regs(
int i,
struct m68k_op *opP,
char *str);
static int reverse_16_bits(
int in);
static int reverse_8_bits(
int in);
static void install_operand(
int mode,
int val);
static void install_gen_operand(
int mode,
int val);
static char *crack_operand(
char *str,
struct m68k_op *opP);
static int get_num(
struct m68k_exp *exp,
int ok);
static
int
m68k_reg_parse(
char **ccp)
{
register char c1,
c2,
c3,
c4;
#ifdef BUILTIN_MMUS
char c5;
#endif
register int n = 0,
ret = 0;
c1=mklower(ccp[0][0]);
c2=mklower(ccp[0][1]);
c3=mklower(ccp[0][2]);
c4=mklower(ccp[0][3]);
#ifdef BUILTIN_MMUS
c5=mklower(ccp[0][4]);
#endif
switch(c1) {
case 'a':
if(c2>='0' && c2<='7') {
n=2;
ret=ADDR+c2-'0';
}
#ifdef m68851
else if (c2 == 'c') {
n = 2;
ret = AC;
}
#endif
break;
#ifdef m68851
case 'b':
if (c2 == 'a') {
if (c3 == 'd') {
if (c4 >= '0' && c4 <= '7') {
n = 4;
ret = BAD + c4 - '0';
}
}
if (c3 == 'c') {
if (c4 >= '0' && c4 <= '7') {
n = 4;
ret = BAC + c4 - '0';
}
}
}
break;
#endif
#ifdef BUILTIN_MMUS
case 'b':
if (c2 == 'c') {
n = 2;
ret = (BC);
}
break;
#endif
case 'c':
#ifdef m68851
if (c2 == 'a' && c3 == 'l') {
n = 3;
ret = CAL;
} else
#endif
if(c2=='c' && c3=='r') {
n=3;
ret = CCR;
} else if(c2=='c') {
n=2;
ret = CCR;
} else if(c2=='a' && (c3=='a' || c3=='c') && c4=='r') {
n=4;
ret = c3=='a' ? CAAR : CACR;
}
#if defined(m68851) || defined (BUILTIN_MMUS)
else if (c2 == 'r' && c3 == 'p') {
n = 3;
ret = (CRP);
}
#endif
break;
case 'd':
if(c2>='0' && c2<='7') {
n=2;
ret = DATA+c2-'0';
} else if(c2=='f' && c3=='c') {
n=3;
ret = DFC;
}
#ifdef m68851
else if (c2 == 'r' && c3 == 'p') {
n = 3;
ret = (DRP);
}
#endif
#ifdef BUILTIN_MMUS
else if (c2 == 't' && c3 == 't' && (c4 == '0' || c4 == '1')) {
n = 4;
if(c4 == '0')
ret = (DTT0);
else
ret = (DTT1);
}
else if (c2 == 'c') {
n = 2;
ret = (DC);
}
#endif
break;
case 'f':
if(c2=='p') {
if(c3>='0' && c3<='7') {
n=3;
ret = FPREG+c3-'0';
if(c4==':')
ccp[0][3]=',';
} else if(c3=='i') {
n=3;
ret = FPI;
} else if(c3=='s') {
n= (c4 == 'r' ? 4 : 3);
ret = FPS;
} else if(c3=='c') {
n= (c4 == 'r' ? 4 : 3);
ret = FPC;
}
}
break;
case 'i':
if(c2=='s' && c3=='p') {
n=3;
ret = ISP;
}
#ifdef BUILTIN_MMUS
else if (c2 == 't' && c3 == 't' && (c4 == '0' || c4 == '1')) {
n = 4;
if(c4 == '0')
ret = (ITT0);
else
ret = (ITT1);
}
else if (c2 == 'c') {
n = 2;
ret = (IC);
}
#endif
break;
case 'm':
if(c2=='s' && c3=='p') {
n=3;
ret = MSP;
}
#ifdef BUILTIN_MMUS
if(c2=='m' && c3=='u' && c4=='s' && c5=='r') {
n=5;
ret = MMUSR;
}
#endif
break;
case 'p':
if(c2=='c') {
#ifdef m68851
if(c3 == 's' && c4=='r') {
n=4;
ret = (PCSR);
} else
#endif
{
n=2;
ret = PC;
}
}
#ifdef m68851
else if (c2 == 's' && c3 == 'r') {
n = 3;
ret = (PSR);
}
#endif
#ifdef BUILTIN_MMUS
else if (c2 == 's' && c3 == 'r') {
n = 3;
ret = (MMUSR);
}
#endif
break;
case 's':
#if defined(m68851) || defined(BUILTIN_MMUS)
if (c2 == 'r' && c3 == 'p') {
n = 3;
ret = (SRP);
}
#endif
#ifdef m68851
else if (c2 == 'c' && c3 == 'c') {
n = 3;
ret = (SCC);
}
#endif
#if defined(m68851) || defined(BUILTIN_MMUS)
else
#endif
if(c2=='r') {
n=2;
ret = SR;
} else if(c2=='p') {
n=2;
ret = ADDR+7;
} else if(c2=='f' && c3=='c') {
n=3;
ret = SFC;
}
break;
#if defined(m68851) || defined(BUILTIN_MMUS)
case 't':
if(c2 == 'c') {
n=2;
ret=TC;
}
#ifdef BUILTIN_MMUS
else if (c2 == 't' && (c3 == '0' || c3 == '1')) {
n = 3;
if(c3 == '0')
ret = (TT0);
else
ret = (TT1);
}
#endif
break;
#endif
case 'u':
if(c2=='s' && c3=='p') {
n=3;
ret = USP;
}
#ifdef BUILTIN_MMUS
else if(c2=='r' && c3=='p') {
n=3;
ret = URP;
}
#endif
break;
case 'v':
#ifdef m68851
if (c2 == 'a' && c3 == 'l') {
n = 3;
ret = (VAL);
} else
#endif
if(c2=='b' && c3=='r') {
n=3;
ret = VBR;
}
break;
case 'z':
if(c2=='p' && c3=='c') {
n=3;
ret = ZPC;
}
break;
default:
break;
}
if(n) {
if(isalnum(ccp[0][n]) || ccp[0][n]=='_')
ret=FAIL;
else
ccp[0]+=n;
} else
ret = FAIL;
return ret;
}
#define SKIP_WHITE() { str++; if(*str==' ') str++;}
static
int
m68k_ip_op(
char *str,
struct m68k_op *opP)
{
char *strend;
int32_t i;
if(*str==' ')
str++;
if(!*str) {
opP->error="Missing operand";
return FAIL;
}
for(strend=str;*strend;strend++)
;
--strend;
if(*str=='#') {
str++;
opP->con1=add_exp(str,strend);
opP->mode=IMMED;
return OK;
}
i=m68k_reg_parse(&str);
if((i==FAIL || *str!='\0') && *str!='@') {
char *stmp;
if(i!=FAIL && (*str=='/' || *str=='-')) {
opP->mode=REGLST;
return get_regs(i,opP,str);
}
if((stmp=index(str,'@'))) {
opP->con1=add_exp(str,stmp-1);
if(stmp==strend) {
opP->mode=AINDX;
return OK;
}
stmp++;
if(*stmp++!='(' || *strend--!=')') {
opP->error="Malformed operand";
return FAIL;
}
i=try_index(&stmp,opP);
opP->con2=add_exp(stmp,strend);
if(i==FAIL) opP->mode=AMIND;
else opP->mode=APODX;
return OK;
}
opP->mode=ABSL;
opP->con1=add_exp(str,strend);
return OK;
}
opP->reg=i;
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;
return OK;
}
if((i<ADDR+0 || i>ADDR+7) && i!=PC && i!=ZPC && i!=FAIL) {
opP->error="Invalid indirect register";
return FAIL;
}
if(*str!='@')
abort();
str++;
switch(*str) {
case '\0':
opP->mode=AINDR;
return OK;
case '-':
opP->mode=ADEC;
return OK;
case '+':
opP->mode=AINC;
return OK;
case '(':
str++;
break;
default:
opP->error="Junk after indirect";
return FAIL;
}
i=try_index(&str,opP);
if(i==FAIL) {
char *beg_str;
beg_str=str;
for(i=1;i;) {
switch(*str++) {
case '\0':
opP->error="Missing )";
return FAIL;
case ',': i=0; break;
case '(': i++; break;
case ')': --i; break;
}
}
opP->con1=add_exp(beg_str,str-2);
if(str[-1]==',') {
i=try_index(&str,opP);
if(i==FAIL) {
opP->error="Malformed index reg";
return FAIL;
}
}
}
if(*str=='\0') {
#ifdef NeXT_MOD
if(opP->reg==FAIL || opP->reg==ZPC) opP->mode=AINDX;
#else
if(opP->reg==FAIL) opP->mode=AINDX;
#endif
else if(opP->ireg==FAIL) opP->mode=AOFF;
else opP->mode=AINDX;
return OK;
}
if(*str!='@' || str[1]!='(') {
opP->error="junk after indirect";
return FAIL;
}
str+=2;
if(opP->ireg!=FAIL) {
opP->mode=APRDX;
i=try_index(&str,opP);
if(i!=FAIL) {
opP->error="Two index registers! not allowed!";
return FAIL;
}
} else
i=try_index(&str,opP);
if(i==FAIL) {
char *beg_str;
beg_str=str;
for(i=1;i;) {
switch(*str++) {
case '\0':
opP->error="Missing )";
return FAIL;
case ',': i=0; break;
case '(': i++; break;
case ')': --i; break;
}
}
opP->con2=add_exp(beg_str,str-2);
if(str[-1]==',') {
if(opP->ireg!=FAIL) {
opP->error="Can't have two index regs";
return FAIL;
}
i=try_index(&str,opP);
if(i==FAIL) {
opP->error="malformed index reg";
return FAIL;
}
opP->mode=APODX;
} else if(opP->ireg!=FAIL)
opP->mode=APRDX;
else
opP->mode=AMIND;
} else
opP->mode=APODX;
if(*str!='\0') {
opP->error="Junk after indirect";
return FAIL;
}
return OK;
}
static
int
try_index(
char **s,
struct m68k_op *opP)
{
register int i;
char *ss;
#define SKIP_W() { ss++; if(*ss==' ') ss++;}
ss= *s;
i=m68k_reg_parse(&ss);
if(!(i>=DATA+0 && i<=ADDR+7)) {
*s=ss;
return FAIL;
}
opP->ireg=i;
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==':') {
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;
}
#ifdef TEST1
void
main(
int argc,
char *argv[],
char *envp[])
{
char buf[128];
struct m68k_op thark;
for(;;){
if(!gets(buf))
break;
memset(&thark, '\0', sizeof(thark));
if(!m68k_ip_op(buf, &thark))
printf("FAIL:");
if(thark.error)
printf("op1 error %s in %s\n",thark.error,buf);
printf("mode %d, reg %d, ",thark.mode,thark.reg);
if(thark.con1)
printf("con1: '%.*s',",
1 + thark.con1->e_end - thark.con1->e_beg,
thark.con1->e_beg);
printf("ireg %d, isiz %d, imul %d ",
thark.ireg, thark.isiz, thark.imul);
if(thark.con2)
printf("con2: '%.*s'",
1 + thark.con2->e_end - thark.con2->e_beg,
thark.con2->e_beg);
printf("\n");
}
exit(0);
}
#endif
static struct hash_control *op_hash = NULL;
static
void
m68_ip(
char *instring)
{
register char *p;
register struct m68k_op *opP;
register struct m68_incant *opcode;
register char *s;
register int tmpreg = 0,
baseo = 0,
outro = 0,
nextword;
int siz1,
siz2;
char c;
int losing;
int opsfound;
LITTLENUM_TYPE words[6];
LITTLENUM_TYPE *wordp;
if (*instring == ' ')
instring++;
for (p = instring; *p != '\0'; p++)
if (*p == ' ')
break;
if (p == instring) {
the_ins.error = "No operator";
the_ins.opcode[0] = 0;
return;
}
c = *p;
*p = '\0';
opcode = (struct m68_incant *)hash_find (op_hash, instring);
*p = c;
if (opcode == NULL) {
the_ins.error = "Unknown operator";
the_ins.opcode[0] = 0;
return;
}
for(opP= &the_ins.operands[0];*p;opP++) {
p = crack_operand (p, opP);
if(opP->error) {
the_ins.error=opP->error;
return;
}
}
opsfound=opP- &the_ins.operands[0];
if(opcode->m_operands[0]=='I') {
int n;
for(n=opsfound;n>0;--n)
the_ins.operands[n]=the_ins.operands[n-1];
memset((char *)(&the_ins.operands[0]), '\0',
sizeof(the_ins.operands[0]));
the_ins.operands[0].mode=MSCR;
the_ins.operands[0].reg=COPNUM;
opsfound++;
}
for(losing=0;;) {
if(opsfound!=opcode->m_opnum)
losing++;
else for(s=opcode->m_operands,opP= &the_ins.operands[0];*s && !losing;s+=2,opP++) {
switch(*s) {
case '!':
if(opP->mode==MSCR || opP->mode==IMMED ||
opP->mode==DREG || opP->mode==AREG || opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST)
losing++;
break;
case '#':
if(opP->mode!=IMMED)
losing++;
else {
int32_t t;
t=get_num(opP->con1,80);
if(s[1]=='b' && !isbyte(t))
losing++;
#ifdef CHECK_WORD_IMMEDIATES
else if((s[1]=='w' || s[1]=='z') &&
!isword(t))
losing++;
#else
else if(s[1]=='z' && !isword(t))
losing++;
#endif
}
break;
case '^':
case 'T':
if(opP->mode!=IMMED)
losing++;
break;
case '$':
if(opP->mode==MSCR || opP->mode==AREG ||
opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
losing++;
break;
case '%':
if(opP->mode==MSCR || opP->reg==PC ||
opP->reg==ZPC || opP->mode==REGLST)
losing++;
break;
case '&':
if(opP->mode==MSCR || opP->mode==DREG ||
opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC ||
opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST)
losing++;
break;
case '*':
if(opP->mode==MSCR || opP->mode==REGLST)
losing++;
break;
case '+':
if(opP->mode!=AINC)
losing++;
break;
case '-':
if(opP->mode!=ADEC)
losing++;
break;
#ifdef NeXT_MOD
case '0':
if(opP->mode!=AINDR)
losing++;
break;
#endif
case '/':
if(opP->mode==MSCR || opP->mode==AREG ||
opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->mode==REGLST)
losing++;
break;
case ';':
if(opP->mode==MSCR || opP->mode==AREG || opP->mode==REGLST)
losing++;
break;
case '?':
if(opP->mode==MSCR || opP->mode==AREG ||
opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->reg==PC ||
opP->reg==ZPC || opP->mode==REGLST)
losing++;
break;
case '@':
if(opP->mode==MSCR || opP->mode==AREG ||
opP->mode==IMMED || opP->mode==REGLST)
losing++;
break;
case '~':
if(opP->mode==MSCR || opP->mode==DREG ||
opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
losing++;
break;
case 'A':
if(opP->mode!=AREG)
losing++;
break;
case 'B':
if(opP->mode!=ABSL)
losing++;
break;
case 'C':
if(opP->mode!=MSCR || opP->reg!=CCR)
losing++;
break;
case 'd':
if(opP->mode!=AOFF && (opP->mode!=ABSL ||
opP->con1->e_beg[0]!='(' || opP->con1->e_end[0]!=')'))
losing++;
break;
case 'D':
if(opP->mode!=DREG)
losing++;
break;
case 'F':
if(opP->mode!=MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7))
losing++;
break;
case 'I':
if(opP->mode!=MSCR || opP->reg<COPNUM ||
opP->reg>=COPNUM+7)
losing++;
break;
case 'J':
#ifdef BUILTIN_MMUS
if(opP->mode!=MSCR || opP->reg<USP || opP->reg>SRP)
#else
if(opP->mode!=MSCR || opP->reg<USP || opP->reg>MSP)
#endif
losing++;
break;
case 'k':
if(opP->mode!=IMMED)
losing++;
break;
case 'l':
case 'L':
if(opP->mode==DREG || opP->mode==AREG || opP->mode==FPREG) {
if(s[1]=='8')
losing++;
else {
opP->mode=REGLST;
opP->reg=1<<(opP->reg-DATA);
}
} else if(opP->mode!=REGLST) {
losing++;
} else if(s[1]=='8' && opP->reg&0x0FFffFF)
losing++;
else if(s[1]=='3' && opP->reg&0x7000000)
losing++;
break;
case 'M':
if(opP->mode!=IMMED)
losing++;
else {
int32_t t;
t=get_num(opP->con1,80);
#ifdef NeXT_MOD
if(! (issbyte(t) && seg(opP->con1)==SEG_ABSOLUTE) )
#else
if(!issbyte(t) || isvar(opP->con1))
#endif
losing++;
}
break;
case 'O':
if(opP->mode!=DREG && opP->mode!=IMMED)
losing++;
break;
case 'Q':
if(opP->mode!=IMMED)
losing++;
else {
int32_t t;
t=get_num(opP->con1,80);
if(t<1 || t>8 || isvar(opP->con1))
losing++;
}
break;
case 'R':
if(opP->mode!=DREG && opP->mode!=AREG)
losing++;
break;
case 's':
if(opP->mode!=MSCR || !(opP->reg==FPI || opP->reg==FPS || opP->reg==FPC))
losing++;
break;
case 'S':
if(opP->mode!=MSCR || opP->reg!=SR)
losing++;
break;
case 'U':
if(opP->mode!=MSCR || opP->reg!=USP)
losing++;
break;
#ifdef m68851
case '|':
if(opP->mode==MSCR || opP->mode==DREG ||
opP->mode==AREG || opP->mode==REGLST)
losing++;
break;
#endif
#if defined(m68851) || defined(BUILTIN_MMUS)
case 'f':
if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC))
losing++;
break;
#endif
#ifdef m68851
case 'P':
if (opP->mode != MSCR || (opP->reg != TC && opP->reg != CAL &&
opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
losing++;
break;
case 'V':
if (opP->reg != VAL)
losing++;
break;
case 'W':
if (opP->mode != MSCR || (opP->reg != DRP && opP->reg != SRP &&
opP->reg != CRP))
losing++;
break;
case 'X':
if (opP->mode != MSCR ||
(!(opP->reg >= BAD && opP->reg <= BAD+7) &&
!(opP->reg >= BAC && opP->reg <= BAC+7)))
losing++;
break;
case 'Y':
if (opP->reg != PSR)
losing++;
break;
case 'Z':
if (opP->reg != PCSR)
losing++;
break;
#endif
#ifdef BUILTIN_MMUS
case 'a':
if ((opP->mode != MSCR) || (opP->reg != SRP &&
opP->reg != CRP && opP->reg != TC))
losing++;
break;
case 'b':
if (opP->mode != MSCR || opP->reg != MMUSR)
losing++;
break;
case 'c':
if ((opP->mode != MSCR) || (opP->reg != IC &&
opP->reg != DC && opP->reg != BC))
losing++;
break;
case 'e':
if ((opP->mode != MSCR) || (opP->reg != TT0 &&
opP->reg != TT1))
losing++;
break;
#endif
default:
as_fatal("Internal error: Operand mode %c unknown",*s);
}
}
if(!losing)
break;
opcode=opcode->m_next;
if(!opcode) {
the_ins.error="instruction/operands mismatch";
return;
}
losing=0;
}
the_ins.args=opcode->m_operands;
the_ins.numargs=opcode->m_opnum;
the_ins.numo=opcode->m_codenum;
the_ins.opcode[0]=getone(opcode);
the_ins.opcode[1]=gettwo(opcode);
#ifdef NeXT_MOD
the_ins.cpus=opcode->m_cpus;
#endif
for(s=the_ins.args,opP= &the_ins.operands[0];*s;s+=2,opP++) {
switch(s[0]) {
case '*':
case '~':
case '%':
case ';':
case '@':
case '!':
case '&':
case '$':
case '?':
case '/':
#ifdef m68851
case '|':
#endif
switch(opP->mode) {
case IMMED:
tmpreg=0x3c;
if(index("bwzl",s[1]))
nextword=get_num(opP->con1,80);
else
nextword=get_num(opP->con1,0);
if(isvar(opP->con1))
add_fix(s[1],opP->con1,0);
switch(s[1]) {
case 'b':
if(!isbyte(nextword))
opP->error="operand out of range";
addword(nextword);
baseo=0;
break;
case 'w':
case 'z':
#ifdef CHECK_WORD_IMMEDIATES
if(!isword(nextword))
opP->error="operand out of range";
#endif
addword(nextword);
baseo=0;
break;
#ifdef NeXT_MOD
case 's':
#endif
case 'l':
addword(nextword>>16);
addword(nextword);
baseo=0;
break;
case 'f':
baseo=2;
outro=8;
break;
case 'F':
baseo=4;
outro=11;
break;
case 'x':
baseo=6;
outro=15;
break;
#ifdef PACKED_IMMEDIATE
case 'p':
baseo=6;
outro= -1;
break;
#endif
default:
as_fatal("Internal error: Can't decode %c%c",*s,s[1]);
}
if(!baseo)
break;
if(seg(opP->con1)!=SEG_BIG) {
int_to_gen(nextword);
gen_to_words(words,baseo,(int32_t)outro);
for(wordp=words;baseo--;wordp++)
addword(*wordp);
break;
}
if(offs(opP->con1)>0) {
#ifndef NeXT_MOD
as_warn("Bignum assumed to be binary bit-pattern");
#endif
if(offs(opP->con1)>baseo) {
as_warn("Bignum too big for %c format; truncated",s[1]);
offs(opP->con1)=baseo;
}
baseo-=offs(opP->con1);
for(wordp=generic_bignum+offs(opP->con1)-1;offs(opP->con1)--;--wordp)
addword(*wordp);
while(baseo--)
addword(0);
break;
}
gen_to_words(words,baseo,(int32_t)outro);
for(wordp=words;baseo--;wordp++)
addword(*wordp);
break;
case DREG:
tmpreg=opP->reg-DATA;
break;
case AREG:
tmpreg=0x08+opP->reg-ADDR;
break;
case AINDR:
#ifdef NeXT_MOD
if(opP->reg==PC){
tmpreg=0x3A;
addword(0x0000);
}
else
#endif
tmpreg=0x10+opP->reg-ADDR;
break;
case ADEC:
tmpreg=0x20+opP->reg-ADDR;
break;
case AINC:
tmpreg=0x18+opP->reg-ADDR;
break;
case AOFF:
if(opP->reg==PC)
tmpreg=0x3A;
else
tmpreg=0x28+opP->reg-ADDR;
nextword=get_num(opP->con1,80);
if(!issword(nextword)) {
if(opP->reg==PC)
tmpreg=0x3B;
else
tmpreg=0x30+opP->reg-ADDR;
addword(0x0170);
if(isvar(opP->con1))
add_fix('l',opP->con1,0);
addword(nextword>>16);
} else if(isvar(opP->con1)) {
if(opP->reg==PC)
tmpreg=0x3B;
else
tmpreg=0x30+opP->reg-ADDR;
addword(0x0170);
if(opP->reg==PC &&
seg(opP->con1) == SEG_DIFFSECT &&
opP->con1-> e_exp.X_subtract_symbol->
sy_frag == frag_now &&
strcmp(opP->con1->
e_exp.X_subtract_symbol->sy_name,
"L0\001") == 0)
opP->con1-> e_exp.X_subtract_symbol->
sy_nlist.n_value += 2;
add_fix('l',opP->con1,0);
addword(nextword>>16);
}
addword(nextword);
break;
case AINDX:
case APODX:
case AMIND:
case APRDX:
nextword=0;
baseo=get_num(opP->con1,80);
outro=get_num(opP->con2,80);
if(opP->reg==PC || opP->reg==ZPC) {
tmpreg=0x3b;
if(opP->reg==ZPC)
nextword|=0x80;
} else if(opP->reg==FAIL) {
nextword|=0x80;
tmpreg=0x30;
} else tmpreg=0x30+opP->reg-ADDR;
siz1= (opP->con1) ? opP->con1->e_siz : 0;
siz2= (opP->con2) ? opP->con2->e_siz : 0;
if(opP->ireg>=DATA+0 && opP->ireg<=ADDR+7) {
nextword|=(opP->ireg-DATA)<<12;
if(opP->isiz==0 || opP->isiz==3)
nextword|=0x800;
switch(opP->imul) {
case 1: break;
case 2: nextword|=0x200; break;
case 4: nextword|=0x400; break;
case 8: nextword|=0x600; break;
default: abort();
}
if(opP->mode==AINDX &&
opP->reg!=FAIL && opP->reg!=ZPC && (siz1==1 || (issbyte(baseo) &&
!isvar(opP->con1)))) {
nextword +=baseo&0xff;
addword(nextword);
if(isvar(opP->con1))
add_fix('B',opP->con1,0);
break;
}
} else
nextword|=0x40;
nextword|=0x100;
switch(siz1) {
case 0:
if(isvar(opP->con1) || !issword(baseo)) {
siz1=3;
nextword|=0x30;
} else if(baseo==0)
nextword|=0x10;
else {
nextword|=0x20;
siz1=2;
}
break;
case 1:
as_warn("Byte dispacement won't work. Defaulting to :w");
case 2:
nextword|=0x20;
break;
case 3:
nextword|=0x30;
break;
}
if(opP->mode!=AINDX) {
switch(siz2) {
case 0:
if(isvar(opP->con2) || !issword(outro)) {
siz2=3;
nextword|=0x3;
} else if(outro==0)
nextword|=0x1;
else {
nextword|=0x2;
siz2=2;
}
break;
case 1:
as_warn("Byte dispacement won't work. Defaulting to :w");
case 2:
nextword|=0x2;
break;
case 3:
nextword|=0x3;
break;
}
if(opP->mode==APODX) nextword|=0x04;
else if(opP->mode==AMIND) nextword|=0x40;
}
addword(nextword);
if(isvar(opP->con1))
add_fix(siz1==3 ? 'l' : 'w',opP->con1,0);
if(siz1==3)
addword(baseo>>16);
if(siz1)
addword(baseo);
if(isvar(opP->con2))
add_fix(siz2==3 ? 'l' : 'w',opP->con2,0);
if(siz2==3)
addword(outro>>16);
if(siz2)
addword(outro);
break;
case ABSL:
nextword=get_num(opP->con1,80);
switch(opP->con1->e_siz) {
case 1:
as_warn("ignoring :b suffix on %*s",
(int)(opP->con1->e_end-opP->con1->e_beg),
opP->con1->e_beg);
case 0:
if(!isvar(opP->con1) &&
issword(offs(opP->con1))) {
tmpreg=0x38;
addword(nextword);
break;
}
if(isvar(opP->con1) &&
!subs(opP->con1) &&
seg(opP->con1) == SEG_SECT &&
frchain_now->frch_nsect ==
opP->con1->e_exp.X_add_symbol->
sy_nlist.n_sect &&
flagseen['m'] == 0 &&
!index("~%&$?", s[0])) {
tmpreg=0x3A;
add_frag(adds(opP->con1),
offs(opP->con1),
TAB(PCREL,SZ_UNDEF));
break;
}
case 3:
if(isvar(opP->con1))
add_fix('l',opP->con1,0);
tmpreg=0x39;
addword(nextword>>16);
addword(nextword);
break;
case 2:
if(isvar(opP->con1))
add_fix('w',opP->con1,0);
tmpreg=0x38;
addword(nextword);
break;
}
break;
case MSCR:
default:
as_bad("unknown/incorrect operand");
}
install_gen_operand(s[1],tmpreg);
break;
case '#':
case '^':
switch(s[1]) {
case 'j':
tmpreg=70;
break;
case '8':
tmpreg=20;
break;
case 'C':
tmpreg=50;
break;
case '3':
default:
tmpreg=80;
break;
}
tmpreg=get_num(opP->con1,tmpreg);
if(isvar(opP->con1))
add_fix(s[1],opP->con1,0);
switch(s[1]) {
case 'b':
if(!isbyte(tmpreg))
opP->error="out of range";
insop(tmpreg);
if(isvar(opP->con1))
the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
break;
#ifdef NeXT_MOD
case 'j':
if(tmpreg < 0 || tmpreg > 0xfff)
opP->error="out of range";
tmpreg&=0xFFF;
install_operand(s[1],tmpreg);
break;
#endif
case 'w':
case 'z':
#ifdef CHECK_WORD_IMMEDIATES
if(!isword(tmpreg))
opP->error="out of range";
#endif
insop(tmpreg);
if(isvar(opP->con1))
the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
break;
case 'l':
insop(tmpreg);
insop(tmpreg>>16);
if(isvar(opP->con1))
the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
break;
case '3':
tmpreg&=0xFF;
#ifdef NeXT_MOD
if (isvar(opP->con1))
the_ins.reloc[the_ins.nrel-1].n =
(opcode->m_codenum) + 1;
#endif
case '8':
case 'C':
install_operand(s[1],tmpreg);
break;
default:
as_fatal("Internal error: Unknown mode #%c",s[1]);
}
break;
case '+':
case '-':
case 'A':
install_operand(s[1],opP->reg-ADDR);
break;
case 'B':
tmpreg = get_num(opP->con1, 80);
switch(s[1]){
case 'g':
if(opP->con1->e_siz){
switch(opP->con1->e_siz){
case 1:
add_fix('B', opP->con1, 1);
break;
case 2:
if(strncmp(instring, "jbsr", 4) == 0){
if(isvar(opP->con1))
add_fix('w', opP->con1, 0);
the_ins.opcode[the_ins.numo-1] = 0x4eb8;
addword(tmpreg);
break;
}
if(strncmp(instring, "jra", 3) == 0){
if(isvar(opP->con1))
add_fix('w', opP->con1, 0);
the_ins.opcode[the_ins.numo-1] = 0x4ef8;
addword(tmpreg);
break;
}
opP->con1->e_exp.X_add_number += 2;
add_fix('w', opP->con1, 1);
addword(0);
break;
case 3:
the_ins.opcode[the_ins.numo-1] |= 0xff;
opP->con1->e_exp.X_add_number += 4;
add_fix('l', opP->con1, 1);
addword(0);
addword(0);
break;
default:
as_fatal("Bad size for expression %d",
opP->con1->e_siz);
}
}
else if(subs(opP->con1)){
the_ins.opcode[the_ins.numo-1] |= 0xff;
add_fix('l', opP->con1, 1);
addword(0);
addword(0);
}
else if(adds(opP->con1)){
if(flagseen['m'] &&
(the_ins.opcode[0] >= 0x6200) &&
(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));
}
}
else{
the_ins.opcode[the_ins.numo-1] |= 0xff;
opP->con1->e_exp.X_add_number += 4;
add_fix('l', opP->con1, 1);
addword(0);
addword(0);
}
break;
case 'w':
if(isvar(opP->con1)){
if((the_ins.opcode[0] & 0xf0f8) ==0x50c8){
add_frag(adds(opP->con1),
offs(opP->con1),
TAB(DBCC, SZ_UNDEF));
break;
}
}
opP->con1->e_exp.X_add_number += 2;
add_fix('w', opP->con1, 1);
addword(0);
break;
case 'c':
if(opP->con1->e_siz){
switch(opP->con1->e_siz){
case 2:
opP->con1->e_exp.X_add_number += 2;
add_fix('w', opP->con1, 1);
addword(0);
break;
case 3:
the_ins.opcode[the_ins.numo-1] |= 0x40;
opP->con1->e_exp.X_add_number += 4;
add_fix('l', opP->con1, 1);
addword(0);
addword(0);
break;
default:
as_bad("Bad size for offset, must be word "
"or long");
break;
}
}
else if(subs(opP->con1)){
the_ins.opcode[the_ins.numo-1] |= 0x40;
add_fix('l', opP->con1, 1);
addword(0);
addword(0);
}
else if(adds(opP->con1)){
add_frag(adds(opP->con1),
offs(opP->con1),
TAB(FBRANCH, SZ_UNDEF));
}
else{
the_ins.opcode[the_ins.numo-1] |= 0x40;
opP->con1->e_exp.X_add_number += 4;
add_fix('l', opP->con1, 1);
addword(0);
addword(0);
}
break;
default:
as_fatal("Internal error: operand type B%c unknown",
s[1]);
}
break;
case 'C':
break;
case 'd':
if(opP->mode==AOFF) {
install_operand('s',opP->reg-ADDR);
} else {
char *tmpP;
tmpP=opP->con1->e_end-2;
opP->con1->e_beg++;
opP->con1->e_end-=4;
baseo=m68k_reg_parse(&tmpP);
if(baseo<ADDR+0 || baseo>ADDR+7) {
as_bad("Unknown address reg, using A0");
baseo=0;
} else baseo-=ADDR;
install_operand('s',baseo);
}
tmpreg=get_num(opP->con1,80);
if(!issword(tmpreg)) {
as_warn("Expression out of range, using 0");
tmpreg=0;
}
addword(tmpreg);
break;
case 'D':
install_operand(s[1],opP->reg-DATA);
break;
case 'F':
install_operand(s[1],opP->reg-FPREG);
break;
case 'I':
tmpreg=1+opP->reg-COPNUM;
if(tmpreg==8)
tmpreg=0;
install_operand(s[1],tmpreg);
break;
case 'J':
switch(opP->reg) {
case SFC:
tmpreg=0;
break;
case DFC:
tmpreg=0x001;
break;
case CACR:
tmpreg=0x002;
break;
case USP:
tmpreg=0x800;
break;
case VBR:
tmpreg=0x801;
break;
case CAAR:
tmpreg=0x802;
break;
case MSP:
tmpreg=0x803;
break;
case ISP:
tmpreg=0x804;
break;
#ifdef BUILTIN_MMUS
case TC:
tmpreg=0x003;
break;
case ITT0:
tmpreg=0x004;
break;
case ITT1:
tmpreg=0x005;
break;
case DTT0:
tmpreg=0x006;
break;
case DTT1:
tmpreg=0x007;
break;
case MMUSR:
tmpreg=0x805;
break;
case URP:
tmpreg=0x806;
break;
case SRP:
tmpreg=0x807;
break;
#endif
default:
abort();
}
install_operand(s[1],tmpreg);
break;
#ifdef NeXT_MOD
case '0':
tmpreg=opP->reg-ADDR;
install_operand(s[1],tmpreg);
break;
#endif
case 'k':
tmpreg=get_num(opP->con1,55);
install_operand(s[1],tmpreg&0x7f);
break;
case 'l':
tmpreg=opP->reg;
if(s[1]=='w') {
if(tmpreg&0x7FF0000)
as_bad("Floating point register in register list");
insop(reverse_16_bits(tmpreg));
} else {
if(tmpreg&0x700FFFF)
as_bad("Wrong register in floating-point reglist");
install_operand(s[1],reverse_8_bits(tmpreg>>16));
}
break;
case 'L':
tmpreg=opP->reg;
if(s[1]=='w') {
if(tmpreg&0x7FF0000)
as_bad("Floating point register in register list");
insop(tmpreg);
} else if(s[1]=='8') {
if(tmpreg&0x0FFFFFF)
as_bad("incorrect register in reglist");
install_operand(s[1],tmpreg>>24);
} else {
if(tmpreg&0x700FFFF)
as_bad("wrong register in floating-point reglist");
else
install_operand(s[1],tmpreg>>16);
}
break;
case 'M':
install_operand(s[1],get_num(opP->con1,60));
break;
case 'O':
tmpreg= (opP->mode==DREG)
? (int)(0x20+opP->reg-DATA)
: (get_num(opP->con1,40)&0x1F);
install_operand(s[1],tmpreg);
break;
case 'Q':
tmpreg=get_num(opP->con1,10);
if(tmpreg==8)
tmpreg=0;
install_operand(s[1],tmpreg);
break;
case 'R':
install_operand(s[1],opP->reg-DATA);
break;
case 's':
if(opP->reg==FPI) tmpreg=0x1;
else if(opP->reg==FPS) tmpreg=0x2;
else if(opP->reg==FPC) tmpreg=0x4;
else abort();
install_operand(s[1],tmpreg);
break;
case 'S':
break;
case 'T':
install_operand(s[1],get_num(opP->con1,30));
break;
case 'U':
break;
#if defined(m68851) || defined(BUILTIN_MMUS)
case 'f':
switch (opP->reg) {
case SFC:
tmpreg=0;
break;
case DFC:
tmpreg=1;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;
#endif
#ifdef BUILTIN_MMUS
case 'a':
switch (opP->reg) {
case SRP:
tmpreg=2;
break;
case CRP:
tmpreg=3;
break;
case TC:
tmpreg=0;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;
case 'b':
switch (opP->reg) {
case MMUSR:
tmpreg=0;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;
case 'c':
switch (opP->reg) {
case IC:
tmpreg=2;
break;
case DC:
tmpreg=1;
break;
case BC:
tmpreg=3;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;
case 'e':
switch (opP->reg) {
case TT0:
tmpreg=2;
break;
case TT1:
tmpreg=3;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;
#endif
#ifdef m68851
case 'P':
switch(opP->reg) {
case TC:
tmpreg=0;
break;
case CAL:
tmpreg=4;
break;
case VAL:
tmpreg=5;
break;
case SCC:
tmpreg=6;
break;
case AC:
tmpreg=7;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;
case 'V':
if (opP->reg == VAL)
break;
abort();
case 'W':
switch(opP->reg) {
case DRP:
tmpreg=1;
break;
case SRP:
tmpreg=2;
break;
case CRP:
tmpreg=3;
break;
default:
abort();
}
install_operand(s[1],tmpreg);
break;
case 'X':
switch (opP->reg) {
case BAD: case BAD+1: case BAD+2: case BAD+3:
case BAD+4: case BAD+5: case BAD+6: case BAD+7:
tmpreg = (4 << 10) | ((opP->reg - BAD) << 2);
break;
case BAC: case BAC+1: case BAC+2: case BAC+3:
case BAC+4: case BAC+5: case BAC+6: case BAC+7:
tmpreg = (5 << 10) | ((opP->reg - BAC) << 2);
break;
default:
abort();
}
install_operand(s[1], tmpreg);
break;
case 'Y':
if (opP->reg == PSR)
break;
abort();
case 'Z':
if (opP->reg == PCSR)
break;
abort();
#endif
default:
as_fatal("Internal error: Operand type %c unknown",s[0]);
}
}
}
static
int
get_regs(
int i,
struct m68k_op *opP,
char *str)
{
uint32_t cur_regs = 0;
int reg1,
reg2;
#define ADD_REG(x) { if(x==FPI) cur_regs|=(1<<24);\
else if(x==FPS) cur_regs|=(1<<25);\
else if(x==FPC) cur_regs|=(1<<26);\
else cur_regs|=(1<<(x-1)); }
reg1=i;
for(;;) {
if(*str=='/') {
ADD_REG(reg1);
str++;
} else if(*str=='-') {
str++;
reg2=m68k_reg_parse(&str);
if(reg2<DATA || reg2>=FPREG+8 || reg1==FPI || reg1==FPS || reg1==FPC) {
opP->error="unknown register in register list";
return FAIL;
}
while(reg1<=reg2) {
ADD_REG(reg1);
reg1++;
}
if(*str=='\0')
break;
} else if(*str=='\0') {
ADD_REG(reg1);
break;
} else {
opP->error="unknow character in register list";
return FAIL;
}
if (*str=='/')
str ++;
reg1=m68k_reg_parse(&str);
if((reg1<DATA || reg1>=FPREG+8) && !(reg1==FPI || reg1==FPS || reg1==FPC)) {
opP->error="unknown register in register list";
return FAIL;
}
}
opP->reg=cur_regs;
return OK;
}
static
int
reverse_16_bits(
int in)
{
int out=0;
int n;
static int mask[16] = {
0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000
};
for(n=0;n<16;n++) {
if(in&mask[n])
out|=mask[15-n];
}
return out;
}
static
int
reverse_8_bits(
int in)
{
int out=0;
int n;
static int mask[8] = {
0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
};
for(n=0;n<8;n++) {
if(in&mask[n])
out|=mask[7-n];
}
return out;
}
static
void
install_operand(
int mode,
int val)
{
switch(mode) {
case 's':
the_ins.opcode[0]|=val & 0xFF;
break;
case 'd':
the_ins.opcode[0]|=val<<9;
break;
case '1':
the_ins.opcode[1]|=val<<12;
break;
case '2':
the_ins.opcode[1]|=val<<6;
break;
case '3':
the_ins.opcode[1]|=val;
break;
case '4':
the_ins.opcode[2]|=val<<12;
break;
case '5':
the_ins.opcode[2]|=val<<6;
break;
case '6':
the_ins.numo++;
the_ins.opcode[2]|=val;
break;
case '7':
the_ins.opcode[1]|=val<<7;
break;
case '8':
the_ins.opcode[1]|=val<<10;
break;
#if defined(m68851) || defined(BUILTIN_MMUS)
case '9':
the_ins.opcode[1]|=val<<5;
break;
#endif
#ifdef BUILTIN_MMUS
case 'S':
the_ins.opcode[0]|=val<<6;
break;
#endif
case 't':
the_ins.opcode[1]|=(val<<10)|(val<<7);
break;
case 'D':
the_ins.opcode[1]|=(val<<12)|val;
break;
case 'g':
the_ins.opcode[0]|=val=0xff;
break;
case 'i':
the_ins.opcode[0]|=val<<9;
break;
case 'C':
the_ins.opcode[1]|=val;
break;
case 'j':
the_ins.opcode[1]|=val;
the_ins.numo++;
break;
case 'k':
the_ins.opcode[1]|=val<<4;
break;
case 'b':
case 'w':
case 'l':
break;
case 'c':
default:
abort();
}
}
static
void
install_gen_operand(
int mode,
int val)
{
switch(mode) {
case 's':
the_ins.opcode[0]|=val;
break;
case 'd':
the_ins.opcode[0]|=(val&0x07)<<9|(val&0x38)<<3;
break;
case 'b':
case 'w':
case 'l':
case 'f':
case 'F':
case 'x':
case 'p':
the_ins.opcode[0]|=val;
break;
default:
abort();
}
}
static
char *
crack_operand(
char *str,
struct m68k_op *opP)
{
register int parens;
register int c;
register char *beg_str;
if(!str) {
return str;
}
beg_str=str;
for(parens=0;*str && (parens>0 || notend(str));str++) {
if(*str == '"') {
str++;
while(*str && *str != '"')
str++;
if(*str != '"'){
opP->error="Missing \"";
return str;
}
}
else{
if(*str=='(')
parens++;
else if(*str==')') {
if(!parens) {
opP->error="Extra )";
return str;
}
--parens;
}
}
}
if(!*str && parens) {
opP->error="Missing )";
return str;
}
c= *str;
*str='\0';
if(m68k_ip_op(beg_str,opP)==FAIL) {
*str=c;
return str;
}
*str=c;
if(c=='}')
c= *++str;
if(c) {
c= *++str;
if(!c)
as_bad("Missing operand");
}
return str;
}
#if 0
notend(s)
char *s;
{
if(*s==',') return 0;
if(*s=='{' || *s=='}')
return 0;
if(*s!=':') return 1;
if(index("aAdD#",s[1])) return 0;
return 1;
}
#endif
#ifdef NeXT_MOD
static char *file_030, *file_040;
static uint32_t line_030, line_040;
#endif
void
md_assemble(
char *str)
{
char *er;
short *fromP;
char *toP = NULL;
int m,n;
char *to_beg_P;
int shorts_this_frag;
n = 0;
memset((char *)(&the_ins), '\0', sizeof(the_ins));
m68_ip(str);
er=the_ins.error;
if(!er) {
for(n=the_ins.numargs;n;--n)
if(the_ins.operands[n].error) {
er=the_ins.operands[n].error;
break;
}
}
if(er) {
as_bad("\"%s\" -- Statement '%s' ignored",er,str);
return;
}
#ifdef NeXT_MOD
if(the_ins.cpus != NULL && !force_cpusubtype_ALL){
if(md_cpusubtype == CPU_SUBTYPE_MC680x0_ALL){
switch(*the_ins.cpus){
case '2':
as_bad("implementation specific instruction for the MC68020"
" and -force_cpusubtype_ALL not specified");
break;
case '3':
if(archflag_cpusubtype == CPU_SUBTYPE_MC68040)
as_bad("030 instruction not allowed with -arch m68040");
else{
file_030 = logical_input_file ?
logical_input_file : physical_input_file;
line_030 = logical_input_line ?
logical_input_line : physical_input_line;
md_cpusubtype = CPU_SUBTYPE_MC68030_ONLY;
}
break;
case '4':
if(archflag_cpusubtype == CPU_SUBTYPE_MC68030_ONLY)
as_bad("040 instruction not allowed with -arch m68030");
else{
file_040 = logical_input_file ?
logical_input_file : physical_input_file;
line_040 = logical_input_line ?
logical_input_line : physical_input_line;
md_cpusubtype = CPU_SUBTYPE_MC68040;
}
break;
}
}
else{
switch(*the_ins.cpus){
case '2':
as_bad("implementation specific instruction for the MC68020"
" and -force_cpusubtype_ALL not specified");
break;
case '3':
if(archflag_cpusubtype == CPU_SUBTYPE_MC68040)
as_bad("030 instruction not allowed with -arch m68040");
else{
if(md_cpusubtype != CPU_SUBTYPE_MC680x0_ALL &&
md_cpusubtype != CPU_SUBTYPE_MC68030_ONLY)
as_bad("more than one implementation specific "
"instruction seen and -force_cpusubtype_ALL "
" not specified (first 040 instruction in: "
"%s at line %u)", file_040, line_040);
md_cpusubtype = CPU_SUBTYPE_MC68030_ONLY;
}
break;
case '4':
if(archflag_cpusubtype == CPU_SUBTYPE_MC68030_ONLY)
as_bad("040 instruction not allowed with -arch m68030");
else{
if(md_cpusubtype != CPU_SUBTYPE_MC680x0_ALL &&
md_cpusubtype != CPU_SUBTYPE_MC68040)
as_bad("more than one implementation specific "
"instruction seen and -force_cpusubtype_ALL "
"not specified (first 030 instruction in: "
"%s at line %u)", file_030, line_030);
md_cpusubtype = CPU_SUBTYPE_MC68040;
}
break;
}
}
}
#endif
#ifdef NeXT_MOD
if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){
(void)symbol_new(
"",
68 ,
text_nsect,
logical_input_line ,
obstack_next_free(&frags) - frag_now->fr_literal,
frag_now);
}
#endif
#ifdef NeXT_MOD
frchain_now->frch_section.flags |= S_ATTR_SOME_INSTRUCTIONS;
#endif
if(the_ins.nfrag==0) {
toP=frag_more(2*the_ins.numo);
fromP= &the_ins.opcode[0];
for(m=the_ins.numo;m;--m) {
md_number_to_chars(toP,(int32_t)(*fromP),2);
toP+=2;
fromP++;
}
for(m=0;m<the_ins.nrel;m++) {
switch(the_ins.reloc[m].wid) {
case 'B':
n=1;
break;
case 'b':
n=1;
break;
case '3':
#ifdef NeXT_MOD
n=1;
#else
n=2;
#endif
break;
case 'w':
n=2;
break;
case 'l':
n=4;
break;
default:
as_fatal("Don't know how to figure width of %c in md_assemble()",the_ins.reloc[m].wid);
}
fix_new(frag_now,
(toP - frag_now->fr_literal) -
the_ins.numo * 2 + the_ins.reloc[m].n,
n,
the_ins.reloc[m].add,
the_ins.reloc[m].sub,
the_ins.reloc[m].off,
the_ins.reloc[m].pcrel,
0,0);
}
return;
}
for(n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) {
int wid;
if(n==0) wid=2*the_ins.fragb[n].fragoff;
else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff);
toP=frag_more(wid);
to_beg_P=toP;
shorts_this_frag=0;
for(m=wid/2;m;--m) {
md_number_to_chars(toP,(int32_t)(*fromP),2);
toP+=2;
fromP++;
shorts_this_frag++;
}
for(m=0;m<the_ins.nrel;m++) {
if((the_ins.reloc[m].n)>= 2*shorts_this_frag ) {
the_ins.reloc[m].n-= 2*shorts_this_frag ;
break;
}
wid=the_ins.reloc[m].wid;
if(wid==0)
continue;
the_ins.reloc[m].wid=0;
wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000;
fix_new(frag_now,
(toP - frag_now->fr_literal) -
the_ins.numo * 2 + the_ins.reloc[m].n,
wid,
the_ins.reloc[m].add,
the_ins.reloc[m].sub,
the_ins.reloc[m].off,
the_ins.reloc[m].pcrel,
0,0);
}
know(the_ins.fragb[n].fadd);
(void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty),
the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P);
}
n=(the_ins.numo-the_ins.fragb[n-1].fragoff);
shorts_this_frag=0;
if(n) {
toP=frag_more(n*sizeof(short));
while(n--) {
md_number_to_chars(toP,(int32_t)(*fromP),2);
toP+=2;
fromP++;
shorts_this_frag++;
}
}
for(m=0;m<the_ins.nrel;m++) {
int wid;
wid=the_ins.reloc[m].wid;
if(wid==0)
continue;
the_ins.reloc[m].wid=0;
wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000;
fix_new(frag_now,
(the_ins.reloc[m].n + toP-frag_now->fr_literal) -
shorts_this_frag * 2,
wid,
the_ins.reloc[m].add,
the_ins.reloc[m].sub,
the_ins.reloc[m].off,
the_ins.reloc[m].pcrel,
0,0);
}
}
void
md_begin(
void)
{
register struct m68k_opcode *ins;
register struct m68_incant *hack,
*slak;
const char *retval = 0;
register int i;
register char c;
if ((op_hash = hash_new()) == NULL)
as_fatal("Virtual memory exhausted");
obstack_begin(&robyn,4000);
for (ins = (struct m68k_opcode *)m68k_opcodes; ins < endop; ins++) {
hack=slak=(struct m68_incant *)obstack_alloc(&robyn,sizeof(struct m68_incant));
do {
slak->m_operands=ins->args;
slak->m_opnum=strlen(slak->m_operands)/2;
slak->m_opcode=ins->opcode;
slak->m_codenum=((ins->match)&0xffffL) ? 2 : 1;
#ifdef NeXT_MOD
slak->m_cpus = ins->cpus;
#endif
if((ins+1)!=endop && !strcmp(ins->name,(ins+1)->name)) {
slak->m_next=(struct m68_incant *)
obstack_alloc(&robyn,sizeof(struct m68_incant));
ins++;
} else
slak->m_next=0;
slak=slak->m_next;
} while(slak);
retval = hash_insert (op_hash, ins->name,(char *)hack);
if(retval && *retval)
as_fatal("Internal Error: Can't hash %s: %s",ins->name,retval);
}
for (i = 0; i < (int)sizeof(mklower_table) ; i++)
mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c;
for (i = 0 ; i < (int)sizeof(notend_table) ; i++) {
notend_table[i] = 0;
alt_notend_table[i] = 0;
}
notend_table[','] = 1;
notend_table['{'] = 1;
notend_table['}'] = 1;
alt_notend_table['a'] = 1;
alt_notend_table['A'] = 1;
alt_notend_table['d'] = 1;
alt_notend_table['D'] = 1;
alt_notend_table['#'] = 1;
alt_notend_table['f'] = 1;
alt_notend_table['F'] = 1;
}
#if 0
#define notend(s) ((*s == ',' || *s == '}' || *s == '{' \
|| (*s == ':' && index("aAdD#", s[1]))) \
? 0 : 1)
#endif
void
md_end(
void)
{
}
#define MAX_LITTLENUMS 6
char *
md_atof(
int type,
char *litP,
int *sizeP)
{
int prec;
LITTLENUM_TYPE words[MAX_LITTLENUMS];
LITTLENUM_TYPE *wordP;
char *t;
switch(type) {
case 'f':
case 'F':
case 's':
case 'S':
prec = 2;
break;
case 'd':
case 'D':
case 'r':
case 'R':
prec = 4;
break;
case 'x':
case 'X':
prec = 6;
break;
case 'p':
case 'P':
prec = 6;
break;
default:
*sizeP=0;
return "Bad call to MD_ATOF()";
}
t=atof_ieee(input_line_pointer,type,words);
if(t)
input_line_pointer=t;
*sizeP=prec * sizeof(LITTLENUM_TYPE);
for(wordP=words;prec--;) {
md_number_to_chars(litP,(int32_t)(*wordP++),sizeof(LITTLENUM_TYPE));
litP+=sizeof(LITTLENUM_TYPE);
}
return "";
}
void
md_number_to_chars(
char *buf,
signed_expr_t val,
int n)
{
switch(n) {
case 1:
*buf++=val;
break;
case 2:
*buf++=(val>>8);
*buf++=val;
break;
case 4:
*buf++=(val>>24);
*buf++=(val>>16);
*buf++=(val>>8);
*buf++=val;
break;
default:
abort();
}
}
void
md_number_to_imm(
unsigned char *buf,
signed_expr_t val,
int n,
fixS *fixP,
int nsect)
{
switch(n) {
case 1:
*buf++=val;
break;
case 2:
*buf++=(val>>8);
*buf++=val;
break;
case 4:
*buf++=(val>>24);
*buf++=(val>>16);
*buf++=(val>>8);
*buf++=val;
break;
default:
abort();
}
}
int
md_estimate_size_before_relax(
fragS *fragP,
int nsect)
{
int old_fix;
old_fix = fragP->fr_fix;
switch(fragP->fr_subtype){
case TAB(DBCC, SZ_UNDEF):
if(fragP->fr_symbol->sy_nlist.n_sect == nsect){
fragP->fr_subtype = TAB(DBCC, SHORT);
fragP->fr_var += 2;
break;
}
fragP->fr_opcode[2] = 0x00;
fragP->fr_opcode[3] = 0x04;
fragP->fr_opcode[4] = 0x60;
fragP->fr_opcode[5] = 0x06;
fragP->fr_opcode[6] = 0x4e;
fragP->fr_opcode[7] = 0xf9;
fragP->fr_fix += 6;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
frag_wane(fragP);
break;
case TAB(BCC68000, SZ_UNDEF):
if(fragP->fr_symbol->sy_nlist.n_sect == nsect){
fragP->fr_subtype = TAB(BCC68000, BYTE);
break;
}
fragP->fr_opcode[0] ^= 0x01;
fragP->fr_opcode[1] = 0x6;
fragP->fr_opcode[2] = 0x4e;
fragP->fr_opcode[3] = 0xf9;
fragP->fr_fix += 2;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
frag_wane(fragP);
break;
case TAB(BRANCH, SZ_UNDEF):
if(fragP->fr_symbol->sy_nlist.n_sect == nsect){
if(fragP->fr_symbol->sy_name[0] != 'L' || flagseen ['L']){
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset + 4,
1,
1,
0);
fragP->fr_fix += 4;
fragP->fr_opcode[1] = 0xff;
frag_wane(fragP);
break;
}
else
fragP->fr_subtype = TAB(BRANCH, BYTE);
break;
}
else if(flagseen['m']){
if(fragP->fr_opcode[0] == 0x61){
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = 0xB9;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
frag_wane(fragP);
}
else if(fragP->fr_opcode[0] == 0x60){
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = 0xF9;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
frag_wane(fragP);
}
else{
as_warn("Long branch offset to extern symbol not "
"supported.");
}
break;
}
else{
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset + 4,
1,
1,
0);
fragP->fr_fix += 4;
fragP->fr_opcode[1] = 0xff;
frag_wane(fragP);
break;
}
break;
case TAB(FBRANCH, SZ_UNDEF):
if(fragP->fr_symbol->sy_nlist.n_sect == nsect){
if(fragP->fr_symbol->sy_name[0] != 'L' || flagseen ['L']) {
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset + 4,
1,
1,
0);
fragP->fr_fix += 4;
fragP->fr_opcode[1] |= 0x40;
frag_wane(fragP);
break;
}
else{
fragP->fr_subtype = TAB(FBRANCH, SHORT);
fragP->fr_var += 2;
}
}
else {
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset + 4,
1,
1,
0);
fragP->fr_fix += 4;
fragP->fr_opcode[1] |= 0x40;
frag_wane(fragP);
break;
}
break;
case TAB(PCREL, SZ_UNDEF):
if(fragP->fr_symbol->sy_nlist.n_sect == nsect){
if(fragP->fr_symbol->sy_name[0] != 'L' || flagseen ['L']) {
if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
as_bad("Internal error (long PC-relative operand) for "
"insn 0x%04x at 0x%llx", fragP->fr_opcode[0],
fragP->fr_address);
fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x39;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
frag_wane(fragP);
}
else{
fragP->fr_subtype = TAB(PCREL, SHORT);
fragP->fr_var += 2;
}
}
else {
if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
as_bad("Internal error (long PC-relative operand) for "
"insn 0x%04x at 0x%llx", fragP->fr_opcode[0],
fragP->fr_address);
fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x39;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
1,
1,
0);
fragP->fr_fix += 4;
frag_wane(fragP);
break;
}
break;
default:
break;
}
switch(fragP->fr_subtype) {
case TAB(BCC68000, BYTE):
case TAB(BRANCH, BYTE):
if(fragP->fr_symbol != NULL &&
fragP->fr_symbol->sy_value == 0 &&
fragP->fr_symbol->sy_frag == fragP->fr_next) {
fragP->fr_subtype = TAB(TABTYPE(fragP->fr_subtype), SHORT);
fragP->fr_var += 2;
}
break;
default:
break;
}
return(fragP->fr_var + fragP->fr_fix - old_fix);
}
void
md_convert_frag(
fragS *fragP)
{
int32_t disp;
int32_t ext;
char *buffer_address;
int object_address;
ext = 0;
buffer_address = fragP->fr_fix + fragP->fr_literal;
object_address = fragP->fr_fix + fragP->fr_address;
know(fragP->fr_symbol);
disp = (fragP->fr_symbol->sy_value + fragP->fr_offset) - object_address;
switch(fragP->fr_subtype){
case TAB(BCC68000, BYTE):
case TAB(BRANCH, BYTE):
know(issbyte(disp));
if(disp == 0){
fragP->fr_opcode[0] = 0x4e;
fragP->fr_opcode[1] = 0x71;
}
else{
fragP->fr_opcode[1] = disp;
}
ext = 0;
break;
case TAB(DBCC, SHORT):
know(issword(disp));
ext=2;
break;
case TAB(BCC68000, SHORT):
case TAB(BRANCH, SHORT):
know(issword(disp));
fragP->fr_opcode[1] = 0x00;
ext = 2;
break;
case TAB(BRANCH,LONG):
if(flagseen['m']){
if(fragP->fr_opcode[0] == 0x61){
fragP->fr_opcode[0] = 0x4E;
fragP->fr_opcode[1] = 0xB9;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
ext = 0;
}
else if(fragP->fr_opcode[0] == 0x60){
fragP->fr_opcode[0]= 0x4E;
fragP->fr_opcode[1]= 0xF9;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
ext = 0;
}
else{
as_bad("Long branch offset not supported.");
}
}
else{
fragP->fr_opcode[1] = 0xff;
ext = 4;
}
break;
case TAB(BCC68000, LONG):
fragP->fr_opcode[0] ^= 0x01;
fragP->fr_opcode[1] = 0x6;
fragP->fr_opcode[2] = 0x4e;
fragP->fr_opcode[3] = 0xf9;
fragP->fr_fix += 2;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
ext = 0;
break;
case TAB(DBCC, LONG):
fragP->fr_opcode[2] = 0x00;
fragP->fr_opcode[3] = 0x04;
fragP->fr_opcode[4] = 0x60;
fragP->fr_opcode[5] = 0x06;
fragP->fr_opcode[6] = 0x4e;
fragP->fr_opcode[7] = 0xf9;
fragP->fr_fix += 6;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
ext = 0;
break;
case TAB(FBRANCH, SHORT):
know((fragP->fr_opcode[1] & 0x40) == 0);
ext = 2;
break;
case TAB(FBRANCH, LONG):
fragP->fr_opcode[1] |= 0x40;
ext = 4;
break;
case TAB(PCREL,SHORT):
ext = 2;
break;
case TAB(PCREL,LONG):
if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
as_bad("Internal error (long PC-relative operand) for insn "
"0x%04x at 0x%llx", fragP->fr_opcode[0],
fragP->fr_address);
fragP->fr_opcode[1] &= ~0x3F;
fragP->fr_opcode[1] |= 0x39;
fix_new(fragP,
fragP->fr_fix,
4,
fragP->fr_symbol,
0,
fragP->fr_offset,
0,
0,
0);
fragP->fr_fix += 4;
ext = 0;
break;
default:
break;
}
if(ext != 0){
md_number_to_chars(buffer_address, (int32_t)disp, (int)ext);
fragP->fr_fix += ext;
}
}
static
int
get_num(
struct m68k_exp *exp,
int ok)
{
#ifdef TEST2
int32_t l = 0;
if(!exp->e_beg)
return 0;
if(*exp->e_beg=='0') {
if(exp->e_beg[1]=='x')
sscanf(exp->e_beg+2,"%x",&l);
else
sscanf(exp->e_beg+1,"%O",&l);
return l;
}
return atol(exp->e_beg);
#else
char *save_in;
char c_save;
if(!exp) {
return 0;
}
if(!exp->e_beg || !exp->e_end) {
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)= (ok==10) ? 1 : 0;
as_warn("Null expression defaults to %lld", offs(exp));
return 0;
}
exp->e_siz=0;
if(exp->e_end[-1]==':' && (exp->e_end-exp->e_beg)>=2) {
switch(exp->e_end[0]) {
case 's':
case 'b':
exp->e_siz=1;
break;
case 'w':
exp->e_siz=2;
break;
case 'l':
exp->e_siz=3;
break;
default:
as_bad("Unknown size for expression \"%c\"",exp->e_end[0]);
}
exp->e_end-=2;
}
c_save=exp->e_end[1];
exp->e_end[1]='\0';
save_in=input_line_pointer;
input_line_pointer=exp->e_beg;
#ifdef NeXT_MOD
(void) expression (&(exp->e_exp));
switch(try_to_make_absolute(&(exp->e_exp))) {
#else
switch(expression(&(exp->e_exp))) {
#endif
case SEG_NONE:
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)=0;
if(ok==10) {
as_warn("expression out of range: defaulting to 1");
offs(exp)=1;
}
break;
case SEG_ABSOLUTE:
switch(ok) {
case 10:
if(offs(exp)<1 || offs(exp)>8) {
as_warn("expression out of range: defaulting to 1");
offs(exp)=1;
}
break;
case 20:
if(offs(exp)<0 || offs(exp)>7)
goto outrange;
break;
case 30:
if(offs(exp)<0 || offs(exp)>15)
goto outrange;
break;
case 40:
if(offs(exp)<0 || offs(exp)>32)
goto outrange;
break;
case 50:
if(offs(exp)<0 || offs(exp)>127)
goto outrange;
break;
case 55:
if(offs(exp)<-64 || offs(exp)>63)
goto outrange;
break;
case 60:
if(offs(exp)<-128 || offs(exp)>127)
goto outrange;
break;
case 70:
if(offs(exp)<0 || offs(exp)>4095) {
outrange:
as_warn("expression out of range: defaulting to 0");
offs(exp)=0;
}
break;
default:
break;
}
break;
case SEG_SECT:
case SEG_UNKNOWN:
case SEG_DIFFSECT:
if(ok>=10 && ok<=70) {
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)= (ok==10) ? 1 : 0;
as_warn("Can't deal with expression \"%s\": defaulting "
"to %lld", exp->e_beg, offs(exp));
}
break;
case SEG_BIG:
#ifndef NeXT_MOD
if(ok==80 && offs(exp)<0) {
LITTLENUM_TYPE words[6];
gen_to_words(words,2,8L);
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)=words[1]|(words[0]<<16);
} else if(ok!=0) {
#else
if(ok!=0) {
#endif
seg(exp)=SEG_ABSOLUTE;
adds(exp)=0;
subs(exp)=0;
offs(exp)= (ok==10) ? 1 : 0;
as_warn("Can't deal with expression \"%s\": defaulting "
"to %lld", exp->e_beg, offs(exp));
}
break;
default:
abort();
}
if(input_line_pointer!=exp->e_end+1)
as_bad("Ignoring junk after expression");
exp->e_end[1]=c_save;
input_line_pointer=save_in;
if(exp->e_siz) {
switch(exp->e_siz) {
case 1:
if(!isbyte(offs(exp)))
as_warn("expression doesn't fit in BYTE");
break;
case 2:
if(!isword(offs(exp)))
as_warn("expression doesn't fit in WORD");
break;
}
}
return offs(exp);
#endif
}
void demand_empty_rest_of_line();
static
void
s_even(
uintptr_t value)
{
register int power_of_2_alignment;
register int32_t temp_fill;
char fill;
power_of_2_alignment = 1;
temp_fill = get_absolute_expression ();
md_number_to_chars(&fill, temp_fill, 1);
frag_align(power_of_2_alignment, &fill, 1, 0);
if(frchain_now->frch_section.align <
(uint32_t)power_of_2_alignment)
frchain_now->frch_section.align = power_of_2_alignment;
demand_empty_rest_of_line();
}
static
void
s_proc(
uintptr_t value)
{
demand_empty_rest_of_line();
}
int
md_parse_option(
char **argP,
int *cntP,
char ***vecP)
{
switch(**argP) {
case 'm':
(*argP)++;
if(**argP=='c')
(*argP)++;
if(!strcmp(*argP,"68000"))
flagseen['m']=2;
else if(!strcmp(*argP,"68010")) {
flagseen['m']=1;
} else if(!strcmp(*argP,"68020"))
flagseen['m']=0;
else
as_warn("Unknown -m option ignored");
while(**argP)
(*argP)++;
break;
default:
return 0;
}
return 1;
}
#ifdef TEST2
static
int
is_label(
char *str)
{
while(*str == ' ')
str++;
while(*str && *str != ' ')
str++;
if(str[-1] == ':' || str[1] == '=')
return(1);
return(0);
}
void
main(
int argc,
char *argv[],
char *envp[])
{
char buf[120];
char *cp;
int n;
m68_ip_begin();
for(;;){
if(!gets(buf) || !*buf)
break;
if(buf[0] == '|' || buf[1] == '.')
continue;
for(cp = buf; *cp; cp++)
if(*cp == '\t')
*cp = ' ';
if(is_label(buf))
continue;
memset(&the_ins, '\0', sizeof(the_ins));
m68_ip(buf);
if(the_ins.error){
printf("Error %s in %s\n", the_ins.error, buf);
}
else{
printf("Opcode(%d.%s): ", the_ins.numo, the_ins.args);
for(n = 0; n < the_ins.numo; n++)
printf(" 0x%x", the_ins.opcode[n] & 0xffff);
printf(" ");
print_the_insn(&the_ins.opcode[0], stdout);
(void)putchar('\n');
}
for(n = 0; n < strlen(the_ins.args) / 2; n++){
if(the_ins.operands[n].error){
printf("op%d Error %s in %s\n",
n, the_ins.operands[n].error, buf);
continue;
}
printf("mode %d, reg %d, ",
the_ins.operands[n].mode, the_ins.operands[n].reg);
if(the_ins.operands[n].con1)
printf("con1: '%.*s', ",
1 + the_ins.operands[n].con1->e_end -
the_ins.operands[n].con1->e_beg,
the_ins.operands[n].con1->e_beg);
printf("ireg %d, isiz %d, imul %d, ",
the_ins.operands[n].ireg,
the_ins.operands[n].isiz,
the_ins.operands[n].imul);
if(the_ins.operands[n].con2)
printf("con2: '%.*s',",
1 + the_ins.operands[n].con2->e_end -
the_ins.operands[n].con2->e_beg,
the_ins.operands[n].con2->e_beg);
(void)putchar('\n');
}
}
m68_ip_end();
}
#endif