178 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
#define RCSID5 "$Header$"
 | 
						|
 | 
						|
settype( type )
 | 
						|
int	type;
 | 
						|
{	oprtype[ operand ] = type;	}
 | 
						|
 | 
						|
 | 
						|
short	twolog( s )
 | 
						|
short	s;
 | 
						|
{	short	twopower = 0;
 | 
						|
	while ( (s>>=1) != 0 )  twopower++;
 | 
						|
	return( twopower );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
setmode( opr )
 | 
						|
short	opr;
 | 
						|
{	mode = modetbl[ twolog( oprtype[opr] ) ] << 12;	}
 | 
						|
 | 
						|
 | 
						|
chtype( opr, typerange )
 | 
						|
short	opr,
 | 
						|
	typerange;
 | 
						|
/* Check type of 'opr' with given 'typerange' and
 | 
						|
** set the global var 'mode'.
 | 
						|
*/
 | 
						|
{	if ( (oprtype[opr] & typerange) != oprtype[opr] )  argerr();
 | 
						|
	else /* We have a permitted type for 'opr'. */  setmode( opr );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
chreg( opc, reg )
 | 
						|
short	opc, reg;
 | 
						|
{	switch( opc ) {
 | 
						|
	case 0xB10A: case 0x1B00: case 0x1900:
 | 
						|
		/* R32 expected	*/  if (reg & 1) regerr();  break;
 | 
						|
	case 0xB107: case 0x1A00: case 0x1800:
 | 
						|
		/* R64 expected	*/  if (reg & 3) regerr();  break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
ATYPE	checkaddr( addr )
 | 
						|
valu_t	addr;
 | 
						|
/* Called by functions emit_ad() and branch().	*/
 | 
						|
{	ATYPE	addr_struct;
 | 
						|
 | 
						|
	addr_struct.seg = addr >> 16;
 | 
						|
	addr_struct.off = addr & 0xFFFF;
 | 
						|
	if ( addr_struct.seg < 0 )  addr_struct.seg = 0;
 | 
						|
#ifdef ASLD
 | 
						|
	else  fit(fit7(addr_struct.seg));
 | 
						|
#endif
 | 
						|
	return( addr_struct );
 | 
						|
}
 | 
						|
 | 
						|
emit_ad( ad_inf )
 | 
						|
expr_t	ad_inf;
 | 
						|
/* When the type of an operand is 'da' or 'x' this function
 | 
						|
** emits the address.
 | 
						|
*/
 | 
						|
{	short	sm;
 | 
						|
	ATYPE	addr;
 | 
						|
 | 
						|
	addr = checkaddr( ad_inf.val );
 | 
						|
		/* Always the long format is emitted, because the binary
 | 
						|
		** will be downloaded into one z8000-segment with offset
 | 
						|
		** 0x0000 upto 0xFFFF,so the chance we can use the short
 | 
						|
		** format is very small.
 | 
						|
		*/
 | 
						|
	emit2( 1<<15 | addr.seg<<8 );
 | 
						|
	emit2( addr.off );		/* ??? relocation information ??? */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
ldmcode( wrd1, wrd2, num )
 | 
						|
int	wrd1, wrd2, num;
 | 
						|
{	fit(fit4(num-1));
 | 
						|
	emit2( mode | wrd1 );
 | 
						|
	emit2( wrd2<<8 | num-1 );
 | 
						|
	if ( mode>>12 == 4 ) emit_ad( addr_inf );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
valu_t	adjust( absval )
 | 
						|
valu_t	absval;
 | 
						|
{	valu_t	val = absval - DOTVAL - 2;
 | 
						|
 | 
						|
	if ( pass == PASS_2 && val > 0 ) val -= DOTGAIN;
 | 
						|
	return( val );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
branch( opc, exp )
 | 
						|
short	opc;
 | 
						|
expr_t	exp;
 | 
						|
/* This routine determines for the F3 format instructions whether the
 | 
						|
** relative address is small enough to fit in normal code; If this is
 | 
						|
** so normal code is emitted otherwise 'long' code is emitted contai-
 | 
						|
** ning the direct address.
 | 
						|
*/
 | 
						|
{	short	longopc = 0, reladdr = 0, sm2, sm4;
 | 
						|
	valu_t	val;
 | 
						|
	ATYPE	addr;
 | 
						|
 | 
						|
	val = adjust(exp.val) >> 1;
 | 
						|
	if ( (exp.typ & ~S_DOT) != DOTTYP )  sm2 = sm4 = 0;
 | 
						|
	else
 | 
						|
	{   switch ( opc & 0xF000 )
 | 
						|
	    {   case DJNZ_: sm2 = fit7( -val );
 | 
						|
			    reladdr = -val;
 | 
						|
			    break;
 | 
						|
		case JR_:   sm2 = fits8( val );
 | 
						|
			    reladdr = low8( val );
 | 
						|
			    longopc = 0x5E00 | (opc>>8 & 0xF);
 | 
						|
			    break;
 | 
						|
		case CALR_: sm2 = fits12( -val );
 | 
						|
			    reladdr = low12( -val );
 | 
						|
			    longopc = 0x5F00;
 | 
						|
			    break;
 | 
						|
	    }
 | 
						|
	    sm4 = sm2 || fit8( (short)exp.val );
 | 
						|
	}
 | 
						|
	switch ( opc & 0xF000 )
 | 
						|
	{   case DJNZ_: fit( sm2 );  /* djnz must be short */
 | 
						|
			emit2( opc | reladdr );
 | 
						|
			break;
 | 
						|
	    case JR_: case CALR_:
 | 
						|
			sm4 = small(sm4, 2);
 | 
						|
			sm2 = small(sm2, 2);
 | 
						|
			if ( sm2 )  emit2( opc | reladdr );
 | 
						|
			else  /* replace by jp/call da */
 | 
						|
			{   emit2( longopc );
 | 
						|
			    addr = checkaddr( exp.val );
 | 
						|
			    if ( sm4 )  /* short-offset */
 | 
						|
				emit2( addr.seg<<8 | addr.off );
 | 
						|
			    else
 | 
						|
			    {   emit2( 1<<15 | addr.seg<<8 );
 | 
						|
				emit2( addr.off );
 | 
						|
			    }
 | 
						|
			}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
ldrel( opc, exp )
 | 
						|
short	opc;
 | 
						|
expr_t	exp;
 | 
						|
/* This routine determines for the F4 format instructions whether the
 | 
						|
** address is within the same segment  (meaning a relative address of
 | 
						|
** less than 16 bits); If this is so normal code is emitted otherwise
 | 
						|
** an error message is given.
 | 
						|
*/
 | 
						|
{	if ( pass >= PASS_2 && (exp.typ & ~S_DOT) != DOTTYP )
 | 
						|
				serror( "relative too far" );
 | 
						|
	emit2( opc );
 | 
						|
	emit2( (short)adjust(exp.val) );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
shiftcode( w1, w2 )
 | 
						|
int	w1, w2;
 | 
						|
{   switch( w1 & 0x0F04 )
 | 
						|
    {   /* Remember: w2 negative means right shift !   */
 | 
						|
        case 0x200: /*byte*/  fit( w2>=-8 && w2<=8 );  break;
 | 
						|
        case 0x300: /*word*/  fit( w2>=-16 && w2<=16 );  break;
 | 
						|
        case 0x304: /*long*/  fit( w2>=-32 && w2<=32 );  break;
 | 
						|
    }
 | 
						|
    emit2( w1 );
 | 
						|
    emit2( w2 );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
argerr()
 | 
						|
{	serror( "illegal operand" );	}
 |