175 lines
3.9 KiB
C
175 lines
3.9 KiB
C
|
#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" ); }
|