541 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			541 lines
		
	
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $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()
 | |
| {
 | |
| 	switch(curr_instr) {
 | |
| 	case MOVEM:
 | |
| 	case FMOVE:
 | |
| 	case FMOVEM:
 | |
| 	case FDYADIC:
 | |
| 	case FMONADIC:
 | |
| 	case FSINCOS:
 | |
| 	case FSCC:
 | |
| 	case FTST:
 | |
| 		return 4;
 | |
| 	}
 | |
| 	return 2;
 | |
| }
 | |
| 
 | |
| ea_1(sz, bits)
 | |
| {
 | |
| 	register 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));
 | |
| }
 | |
| 
 | |
| ea_2(sz, bits)
 | |
| { 
 | |
| 	mrg_1 = mrg_2;
 | |
| 	exp_1 = exp_2;
 | |
| 	RELOMOVE(rel_1, rel_2);
 | |
| 	ea_1(sz, bits);
 | |
| }
 | |
| 
 | |
| index(hibyte)
 | |
| {
 | |
| 	Xfit(fitb(exp_2.val));
 | |
| 	exp_2.val = hibyte | lowb(exp_2.val);
 | |
| }
 | |
| 
 | |
| checksize(sz, bits)
 | |
| {
 | |
| 	if ((bits & (1 << (sz>>6))) == 0)
 | |
| 		serror("bad size");
 | |
| }
 | |
| 
 | |
| test68010()
 | |
| {
 | |
| 	if (model != 1 && pass == PASS_3)
 | |
| 		warning("68010 instruction");
 | |
| }
 | |
| 
 | |
| badoperand()
 | |
| {
 | |
| 	serror("bad operands");
 | |
| }
 | |
| 
 | |
| shift_op(opc, 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);
 | |
| }
 | |
| 
 | |
| bitop(opc)
 | |
| {
 | |
| 	register 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();
 | |
| }
 | |
| 
 | |
| add(opc, 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();
 | |
| }
 | |
| 
 | |
| and(opc, 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();
 | |
| }
 | |
| 
 | |
| to_dreg(opc, sz, bits)
 | |
| {
 | |
| 	if ((mrg_2 & 070) != 000)
 | |
| 		return(0);
 | |
| 	emit2((opc & 0170000) | sz | (mrg_2&7)<<9 | mrg_1);
 | |
| 	ea_1(sz, bits);
 | |
| 	return(1);
 | |
| }
 | |
| 
 | |
| from_dreg(opc, sz, 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);
 | |
| }
 | |
| 
 | |
| cmp(sz)
 | |
| {
 | |
| 	register 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();
 | |
| }
 | |
| 
 | |
| move(sz)
 | |
| {
 | |
| 	register 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);
 | |
| }
 | |
| 
 | |
| move_special(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(regs, max)
 | |
| 	register int regs;
 | |
| {
 | |
| 	register int r, i;
 | |
| 
 | |
| 	r = regs; regs = 0;
 | |
| 	for (i = max; i > 0; i--) {
 | |
| 		regs <<= 1;
 | |
| 		if (r & 1) regs++;
 | |
| 		r >>= 1;
 | |
| 	}
 | |
| 	return regs;
 | |
| }
 | |
| 
 | |
| movem(dr, sz, regs)
 | |
| {
 | |
| 	register 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);
 | |
| }
 | |
| 
 | |
| movep(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();
 | |
| }
 | |
| 
 | |
| branch(opc, exp)
 | |
| expr_t exp;
 | |
| {
 | |
| 	register 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));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| ea5x73(rg, 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);
 | |
| 		index(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();
 | |
| }
 | |
| 
 | |
| ea707172(sz)
 | |
| {
 | |
| 	register 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;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| ea6x(rg, ir, sz)
 | |
| {
 | |
| 	mrg_2 = 060 | rg;
 | |
| 	checksize(sz, 2|4);
 | |
| 	index(ir<<12 | (sz&0200)<<4);
 | |
| }
 | |
| 
 | |
| ea72()
 | |
| {
 | |
| 	mrg_2 = 072;
 | |
| 	exp_2.val -= (DOTVAL + extension_offset());
 | |
| }
 | |
| 
 | |
| ea73(ri, sz)
 | |
| {
 | |
| 	mrg_2 = 073;
 | |
| 	exp_2.val -= (DOTVAL + extension_offset());
 | |
| 	checksize(sz, 2|4);
 | |
| 	index(ri<<12 | (sz&0200)<<4);
 | |
| }
 | |
| 
 | |
| Xnofit()
 | |
| {
 | |
| 	if (pass == PASS_3) serror("too big");
 | |
| }
 | |
| 
 | |
| fbranch(opc, exp)
 | |
| expr_t exp;
 | |
| {
 | |
| 	register 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);
 | |
| }
 | |
| 
 | |
| ch_sz_dreg(size, mode)
 | |
| {
 | |
| 	if (mode == 0 &&
 | |
| 	    (size == FSIZE_X || size == FSIZE_P || size == FSIZE_D))
 | |
| 		serror("illegal size for data register");
 | |
| }
 | |
| 
 | |
| check_fsize(sz, size)
 | |
| {
 | |
| 	if (sz != size) serror("bad size");
 | |
| }
 |