/* $Id$ */ /* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". */ /* @(#)mach5.c 1.16 */ /* * Motorola 68000/68010 auxiliary functions */ static int extension_offset(void) { switch(curr_instr) { case MOVEM: case FMOVE: case FMOVEM: case FDYADIC: case FMONADIC: case FSINCOS: case FSCC: case FTST: return 4; } return 2; } void ea_1(int sz, int bits) { register int flag; if (mrg_1 > 074) serror("no specials"); if ((flag = eamode[mrg_1>>3]) == 0) if ((flag = eamode[010 + (mrg_1&07)]) == 0) flag = eamode[015 + (sz>>6)]; if ((mrg_1 & 070) == 010) checksize(sz, 2|4); bits &= ~flag; if (bits) serror("bad addressing category"); if (flag & FITW) Xfit (fitw(exp_1.val) || (mrg_1 == 074 && fit16(exp_1.val)) ) ; if (flag & FITB) { Xfit (fitb(exp_1.val) || (mrg_1 == 074 && fit8(exp_1.val)) ); if (mrg_1 == 074) exp_1.val &= 0xFF; } #ifdef RELOCATION RELOMOVE(relonami, rel_1); if (flag & ~0xFF) newrelo(exp_1.typ, (flag>>8) | RELBR | RELWR); #endif if (flag & PUTL) emit4(exp_1.val); if (flag & PUTW) emit2(loww(exp_1.val)); } void ea_2(int sz, int bits) { mrg_1 = mrg_2; exp_1 = exp_2; RELOMOVE(rel_1, rel_2); ea_1(sz, bits); } void indexmode(int hibyte) { Xfit(fitb(exp_2.val)); exp_2.val = hibyte | lowb(exp_2.val); } void checksize(int sz, int bits) { if ((bits & (1 << (sz>>6))) == 0) serror("bad size"); } void test68010(void) { if (model != 1 && pass == PASS_3) warning("68010 instruction"); } void badoperand(void) { serror("bad operands"); } void shift_op(int opc, int sz) { if (mrg_1 < 010 && mrg_2 < 010) { emit2((opc&0170470) | sz | mrg_1<<9 | mrg_2); return; } if (exp_1.typ != S_ABS || mrg_1 != 074) { badoperand(); return; } if (mrg_2 < 010) { Xfit(fit3(exp_1.val)); emit2((opc&0170430) | sz | low3(exp_1.val)<<9 | mrg_2); return; } checksize(sz, 2); Xfit(exp_1.val == 1); emit2((opc&0177700) | mrg_2); ea_2(SIZE_W, MEM|ALT); } void bitop(int opc) { register int bits; bits = DTA|ALT; if (opc == 0 && (mrg_1 < 010 || mrg_2 != 074)) bits = DTA; if (mrg_1 < 010) { emit2(opc | 0400 | mrg_1<<9 | mrg_2); ea_2(0, bits); return; } if (mrg_1 == 074) { emit2(opc | 04000 | mrg_2); ea_1(SIZE_W, 0); ea_2(0, bits); return; } badoperand(); } void add(int opc, int sz) { if ((mrg_2 & 070) == 010) checksize(sz, 2|4); if ( mrg_1 == 074 && small( exp_1.typ==S_ABS && fit3(exp_1.val), sz==SIZE_L ? 4 : 2 ) ) { emit2((opc&0400) | 050000 | low3(exp_1.val)<<9 | sz | mrg_2); ea_2(sz, ALT); return; } if (mrg_1 == 074 && (mrg_2 & 070) != 010) { emit2((opc&03000) | sz | mrg_2); ea_1(sz, 0); ea_2(sz, DTA|ALT); return; } if ((mrg_2 & 070) == 010) { emit2((opc&0170300) | (mrg_2&7)<<9 | sz<<1 | mrg_1); ea_1(sz, 0); return; } if (to_dreg(opc, sz, 0)) return; if (from_dreg(opc, sz, ALT|MEM)) return; badoperand(); } void and(int opc, int sz) { if (mrg_1 == 074 && mrg_2 >= 076) { /* ccr or sr */ if (sz != SIZE_NON) checksize(sz, mrg_2==076 ? 1 : 2); else sz = (mrg_2==076 ? SIZE_B : SIZE_W); emit2((opc&07400) | sz | 074); ea_1(sz, 0); return; } if (sz == SIZE_NON) sz = SIZE_DEF; if (mrg_1 == 074) { emit2((opc&07400) | sz | mrg_2); ea_1(sz, 0); ea_2(sz, DTA|ALT); return; } if ((opc & 010000) == 0 && to_dreg(opc, sz, DTA)) return; if (from_dreg(opc, sz, (opc & 010000) ? DTA|ALT : ALT|MEM)) return; badoperand(); } int to_dreg(int opc, int sz, int bits) { if ((mrg_2 & 070) != 000) return(0); emit2((opc & 0170000) | sz | (mrg_2&7)<<9 | mrg_1); ea_1(sz, bits); return(1); } int from_dreg(int opc, int sz, int bits) { if ((mrg_1 & 070) != 000) return(0); emit2((opc & 0170000) | sz | (mrg_1&7)<<9 | 0400 | mrg_2); ea_2(sz, bits); return(1); } void cmp(int sz) { register int opc; if ((mrg_1&070) == 030 && (mrg_2&070) == 030) { emit2(0130410 | sz | (mrg_1&7) | (mrg_2&7)<<9); return; } if (mrg_1 == 074 && (mrg_2 & 070) != 010) { if (mrg_2 == 072) { /* In this case, the ea707172 routine changed the addressing mode to PC-relative. However, this is not allowed for this instruction. Change it back to absolute, but also correct for the optimization that the ea707172 routine thought it made. */ if (pass == PASS_1) { /* In this case, the user wrote it PC-relative. Error. */ badoperand(); } mrg_2 = 071; exp_2.val += DOTVAL+2; if (pass == PASS_2) { DOTGAIN -= 2; } } emit2(06000 | sz | mrg_2); ea_1(sz, 0); ea_2(sz, DTA|ALT); return; } if (mrg_2 < 020) { if (mrg_2 >= 010) { checksize(sz, 2|4); opc = 0130300 | sz<<1; mrg_2 &= 7; } else opc = 0130000 | sz; emit2(opc | mrg_2<<9 | mrg_1); ea_1(sz, 0); return; } badoperand(); } void move(int sz) { register int opc; if (mrg_1 > 074 || mrg_2 > 074) { move_special(sz); return; } if (sz == SIZE_NON) sz = SIZE_DEF; if ( mrg_2<010 && mrg_1==074 && sz==SIZE_L && small(exp_1.typ==S_ABS && fitb(exp_1.val), 4) ) { emit2(070000 | mrg_2<<9 | lowb(exp_1.val)); return; } switch (sz) { case SIZE_B: opc = 010000; break; case SIZE_W: opc = 030000; break; case SIZE_L: opc = 020000; break; } emit2(opc | mrg_1 | (mrg_2&7)<<9 | (mrg_2&070)<<3); ea_1(sz, 0); ea_2(sz, ALT); } void move_special(int sz) { if (mrg_2 >= 076) { if (sz != SIZE_NON) checksize(sz, 2); emit2(042300 | (mrg_2==076?0:01000) | mrg_1); ea_1(SIZE_W, DTA); return; } if (mrg_1 >= 076) { if (mrg_1 == 076) test68010(); if (sz != SIZE_NON) checksize(sz, 2); emit2(040300 | (mrg_1==076?01000:0) | mrg_2); ea_2(SIZE_W, DTA|ALT); return; } if (sz != SIZE_NON) checksize(sz, 4); if (mrg_1==075 && (mrg_2&070)==010) { emit2(047150 | (mrg_2&7)); return; } if (mrg_2==075 && (mrg_1&070)==010) { emit2(047140 | (mrg_1&7)); return; } badoperand(); } int reverse(register int regs, int max) { register int r, i; r = regs; regs = 0; for (i = max; i > 0; i--) { regs <<= 1; if (r & 1) regs++; r >>= 1; } return regs; } void movem(int dr, int sz, int regs) { register int i; if ((mrg_2>>3) == 04) { regs = reverse(regs, 16); } checksize(sz, 2|4); if ((mrg_2>>3)-3 == dr) badoperand(); emit2(044200 | dr<<10 | (sz & 0200) >> 1 | mrg_2); emit2(regs); i = CTR; if (dr == 0 && (mrg_2&070) == 040) i = MEM; if (dr != 0 && (mrg_2&070) == 030) i = MEM; if (dr == 0) i |= ALT; ea_2(sz, i); } void movep(int sz) { checksize(sz, 2|4); if (mrg_1<010 && (mrg_2&070)==050) { emit2(0610 | (sz & 0200)>>1 | mrg_1<<9 | (mrg_2&7)); ea_2(sz, 0); return; } if (mrg_2<010 && (mrg_1&070)==050) { emit2(0410 | (sz & 0200)>>1 | mrg_2<<9 | (mrg_1&7)); ea_1(sz, 0); return; } badoperand(); } void branch(int opc, expr_t exp) { register int sm; exp.val -= (DOTVAL + 2); if ((pass == PASS_2) && (exp.val > 0) && ((exp.typ & S_DOT) == 0) ) exp.val -= DOTGAIN; sm = fitb(exp.val); if ((exp.typ & ~S_DOT) != DOTTYP) sm = 0; if (small(sm,2)) { if (exp.val == 0) emit2(047161); /* NOP */ else emit2(opc | lowb(exp.val)); } else { Xfit(fitw(exp.val)); emit2(opc); #ifdef RELOCATION newrelo(exp.typ, RELPC|RELO2|RELBR|RELWR); #endif emit2(loww(exp.val)); } } void ea5x73(int rg, int sz) { if ((exp_2.typ & ~S_DOT) == DOTTYP) { /* pc relative with index */ if (sz == SIZE_NON) sz = SIZE_DEF; exp_2.val -= (DOTVAL + extension_offset()); mrg_2 = 073; checksize(sz, 2|4); indexmode(rg<<12 | (sz&0200)<<4); return; } /* displacement */ mrg_2 = 050 | rg; if (pass == PASS_1) /* tricky, maybe 073 in next passes */ return; if ((rg & 010) == 0 || sz != SIZE_NON) badoperand(); } void ea707172(int sz) { register int sm; mrg_2 = 071; switch (sz) { case SIZE_B: badoperand(); case SIZE_W: mrg_2 = 070; case SIZE_L: return; case SIZE_NON: break; } if (pass == PASS_1) { /* * reserve a bit in the bittable * in the following passes one call to small() * will be done, but we don't know which one * since exp_2.typ cannot be trusted */ small(0, 2); return; } if ((exp_2.typ & ~S_DOT) == DOTTYP) { int off = extension_offset(); sm = fitw(exp_2.val-(DOTVAL+off)); sm = small(sm, 2); if (sm) { /* pc relative */ exp_2.val -= (DOTVAL+off); mrg_2 = 072; } } else { sm = fitw(exp_2.val); #ifdef ASLD if (exp_2.typ & S_VAR) sm = 0; #else if (exp_2.typ != S_ABS) sm = 0; #endif /* ASLD */ sm = small(sm, 2); if (sm) mrg_2 = 070; } } void ea6x(int rg, int ir, int sz) { mrg_2 = 060 | rg; checksize(sz, 2|4); indexmode(ir<<12 | (sz&0200)<<4); } void ea72(void) { mrg_2 = 072; exp_2.val -= (DOTVAL + extension_offset()); } void ea73(int ri, int sz) { mrg_2 = 073; exp_2.val -= (DOTVAL + extension_offset()); checksize(sz, 2|4); indexmode(ri<<12 | (sz&0200)<<4); } void Xnofit(void) { if (pass == PASS_3) serror("too big"); } void fbranch(int opc, expr_t exp) { register int sm; exp.val -= (DOTVAL + 2); if ((pass == PASS_2) && (exp.val > 0) && ((exp.typ & S_DOT) == 0) ) exp.val -= DOTGAIN; sm = fitw(exp.val); if ((exp.typ & ~S_DOT) != DOTTYP) sm = 0; if (small(sm,2)) { emit2(0170200|co_id|opc); emit2(loww(exp.val)); return; } emit2(0170300|co_id|opc); /* 4 byte offset */ #ifdef RELOCATION newrelo(exp.typ, RELPC|RELO4|RELBR|RELWR); #endif emit4(exp.val); } void ch_sz_dreg(int size, int mode) { if (mode == 0 && (size == FSIZE_X || size == FSIZE_P || size == FSIZE_D)) serror("illegal size for data register"); } void check_fsize(int sz, int size) { if (sz != size) serror("bad size"); }