376 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			376 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <string.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include "as.h"
 | 
						|
#include "arg_type.h"
 | 
						|
 | 
						|
 | 
						|
process_label() {}
 | 
						|
 | 
						|
 | 
						|
process_mnemonic( m)
 | 
						|
char *m;
 | 
						|
{
 | 
						|
	for ( ; *m != '\0'; m++)
 | 
						|
		if ( *m == '.')
 | 
						|
			*m = '_';
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
process_operand( str, op)
 | 
						|
register char *str;
 | 
						|
register struct t_operand *op;
 | 
						|
{
 | 
						|
	char *glob_lbl(), *strindex();
 | 
						|
 | 
						|
	op->type = 0;
 | 
						|
 | 
						|
	switch ( *str) {
 | 
						|
	  case '#' : op->type = IS_IMMEDIATE;
 | 
						|
		     op->expr = str+1;
 | 
						|
 | 
						|
		     if ( *(op->expr) != '$') {			/*  #1  */
 | 
						|
			op->val = atoi( str+1);
 | 
						|
			if ( 1 <= op->val  &&  op->val <= 8 ) {
 | 
						|
				op->type = IS_QUICK;
 | 
						|
				op->lbl = NULL;
 | 
						|
			}
 | 
						|
		     }
 | 
						|
		     else 
 | 
						|
			if ( arg_type( str+1) == STRING) {	/*  #$1+$2  */
 | 
						|
				op->lbl = op->expr;
 | 
						|
				*(op->lbl+2) = '\0';
 | 
						|
				op->expr = op->lbl+3;
 | 
						|
		     	}
 | 
						|
		     	else					/*  #$1  */
 | 
						|
				op->lbl = NULL;
 | 
						|
		     break;
 | 
						|
 | 
						|
	  case '(' : if ( strindex( str+1, ',') == NULL)
 | 
						|
			if ( is_reg( str+1)) {
 | 
						|
				op->reg = reg_val( str+1);
 | 
						|
 | 
						|
				if ( *(str+4) == '+')		/*  (sp)+  */
 | 
						|
					op->type = IS_INCR;
 | 
						|
				else				/*  (a0)  */
 | 
						|
					op->type = IS_IND_REG;
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				op->type = IS_IND_MEM;
 | 
						|
				op->expr = str+1;
 | 
						|
				for ( str++; *++str != ')';)
 | 
						|
					;
 | 
						|
				*str = '\0';
 | 
						|
 | 
						|
				if ( *(op->expr) == '$')
 | 
						|
					if ( arg_type( op->expr) == STRING) {
 | 
						|
								/*  ($1+$2)  */
 | 
						|
						op->lbl = op->expr;
 | 
						|
						if ( strlen( op->lbl) == 2) 
 | 
						|
							op->expr = "0";
 | 
						|
						else {
 | 
						|
							*(op->lbl+2) = '\0';
 | 
						|
							op->expr = op->lbl+3;
 | 
						|
						}
 | 
						|
		     			}
 | 
						|
		     			else			/*  ($1)  */
 | 
						|
						op->lbl = NULL;
 | 
						|
				else if ( isdigit( *(op->expr))) /*  (1)  */
 | 
						|
					op->lbl = NULL;
 | 
						|
				else {				/*  (.trppc) */
 | 
						|
					op->lbl = glob_lbl( op->expr);
 | 
						|
					op->expr = "0";
 | 
						|
				}
 | 
						|
			}
 | 
						|
		     else
 | 
						|
			if ( *(str+1) == '[') {
 | 
						|
				op->type = IS_IND_IND;
 | 
						|
				op->expr = str+2;
 | 
						|
				for ( str += 2; *++str != ',';)
 | 
						|
					;
 | 
						|
				*str++ = '\0';
 | 
						|
				for ( ; *str == ' '; str++)
 | 
						|
					;
 | 
						|
				op->reg = reg_val( str);
 | 
						|
 | 
						|
				for ( ; *str++ != ']';)
 | 
						|
					;
 | 
						|
				if ( *str == ')')	/*  ([$1, a6])  */
 | 
						|
					op->expr2 = 0;
 | 
						|
				else {			/*  ([8,a6],8)  */
 | 
						|
					for ( ; *str++ != ',';)
 | 
						|
						;
 | 
						|
					for ( ; *str == ' '; str++)
 | 
						|
						;
 | 
						|
					op->expr2 = atoi( str);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				op->expr = str+1;
 | 
						|
				for ( str++; *++str != ',';)
 | 
						|
					;
 | 
						|
				*str++ = '\0';
 | 
						|
				for ( ; *str == ' '; str++)
 | 
						|
					;
 | 
						|
				op->reg = reg_val( str);
 | 
						|
				if ( *(str+2) == ')')		/*  (4, a0)  */
 | 
						|
					op->type = IS_IND_REG_DISPL;
 | 
						|
				else {			 /*  (0, sp, d0.l*1)  */
 | 
						|
					op->type = IS_3_OPS;
 | 
						|
					for ( str++; *++str != ',';)
 | 
						|
						;
 | 
						|
					for ( ; *str == ' '; str++)
 | 
						|
						;
 | 
						|
					op->reg2 = reg_val( str);
 | 
						|
 | 
						|
					for ( ; *str++ != '*';)
 | 
						|
						;
 | 
						|
					op->scale = atoi( str);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		     break;
 | 
						|
 | 
						|
	  case '-' : op->type = IS_DECR;			/*  -(sp)  */
 | 
						|
		     op->reg = reg_val( str+2);
 | 
						|
		     break;
 | 
						|
 | 
						|
	  case '$' : op->type = IS_GLOB_LBL;			/*  $1  */
 | 
						|
		     op->lbl = str;
 | 
						|
		     op->expr ="0";
 | 
						|
		     break;
 | 
						|
 | 
						|
	  default  : if ( is_reg( str)) {
 | 
						|
			op->reg = reg_val( str);
 | 
						|
			if ( *(str+2) == ':') {			/*  d2:d1  */
 | 
						|
				op->type = IS_REG_PAIR;
 | 
						|
				op->reg2 = reg_val( str+3);
 | 
						|
			}
 | 
						|
			else					/*  a6  */
 | 
						|
				op->type = ( *str == 'd' ? IS_D_REG : IS_A_REG);
 | 
						|
		     }
 | 
						|
		     else if ( isdigit( *str)) {		/*  1f  */
 | 
						|
			op->type = IS_LOC_LBL;
 | 
						|
			op->lbl = str;
 | 
						|
			op->expr = "0";
 | 
						|
			*(str+1) ='\0';
 | 
						|
		     }
 | 
						|
		     else {					/*  .strhp  */
 | 
						|
			op->type = IS_GLOB_LBL;
 | 
						|
			op->lbl = glob_lbl( str);
 | 
						|
			*(str+1) ='\0';
 | 
						|
			op->expr = "0";
 | 
						|
		     }
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int reg_val( reg)
 | 
						|
char *reg;
 | 
						|
{
 | 
						|
	return( *reg == 's' ? 7 : atoi( reg+1));
 | 
						|
}
 | 
						|
 | 
						|
int is_reg( str)
 | 
						|
register char *str;
 | 
						|
{
 | 
						|
	switch ( *str) {
 | 
						|
	  case 'a' :
 | 
						|
	  case 'd' : return( isdigit( *(str+1)));
 | 
						|
 | 
						|
	  case 's' : return( *(str+1) == 'p');
 | 
						|
 | 
						|
	  default  : return( 0);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
char *glob_lbl( lbl)
 | 
						|
char *lbl;
 | 
						|
{
 | 
						|
	char *gl, *Malloc();
 | 
						|
 | 
						|
	gl = Malloc( strlen( lbl) + 3);
 | 
						|
	sprintf( gl, "\"%s\"", lbl);
 | 
						|
	return( gl);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/******************************************************************************/
 | 
						|
 | 
						|
 | 
						|
int mode_reg( eaddr)
 | 
						|
register struct t_operand *eaddr;
 | 
						|
{
 | 
						|
	switch ( eaddr->type) {
 | 
						|
	  case IS_A_REG         : return( 0x08 | eaddr->reg);
 | 
						|
 | 
						|
	  case IS_D_REG         : return( 0x00 | eaddr->reg);
 | 
						|
 | 
						|
	  case IS_IND_REG       : return( 0x10 | eaddr->reg);
 | 
						|
 | 
						|
	  case IS_INCR          : return( 0x18 | eaddr->reg);
 | 
						|
 | 
						|
	  case IS_DECR          : return( 0x20 | eaddr->reg);
 | 
						|
 | 
						|
	  case IS_IND_MEM       : return( 0x39);
 | 
						|
 | 
						|
	  case IS_IND_IND       : return( 0x30 | eaddr->reg);
 | 
						|
 | 
						|
	  case IS_IND_REG_DISPL : return( 0x28 | eaddr->reg);
 | 
						|
 | 
						|
	  case IS_GLOB_LBL      : return( 0x39);
 | 
						|
 | 
						|
	  case IS_3_OPS         : if ( isdigit( *(eaddr->expr)) &&
 | 
						|
				                    atoi( eaddr->expr) < 128)
 | 
						|
					return( 0x30 | eaddr->reg);
 | 
						|
				  else
 | 
						|
					fprintf( stderr, "FOUT in IS_3_OPS\n");
 | 
						|
				  break;
 | 
						|
 | 
						|
	  case IS_QUICK		:
 | 
						|
	  case IS_IMMEDIATE	: return( 0x3c);
 | 
						|
 | 
						|
	  default		: fprintf( stderr,
 | 
						|
					   "mode_reg(), verkeerde operand %d\n",
 | 
						|
					   eaddr->type);
 | 
						|
				  abort();
 | 
						|
				  break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
code_extension( eaddr)
 | 
						|
register struct t_operand *eaddr;
 | 
						|
{
 | 
						|
 | 
						|
	switch ( eaddr->type) {
 | 
						|
	  case IS_IND_MEM       : if ( eaddr->lbl == NULL) 
 | 
						|
					@text4( %$( eaddr->expr));
 | 
						|
				  else
 | 
						|
					@reloc4( %$( eaddr->lbl),
 | 
						|
						 %$( eaddr->expr),
 | 
						|
						 ABSOLUTE);
 | 
						|
				  break;
 | 
						|
 | 
						|
	  case IS_IND_IND       : if ( eaddr->expr2 == 0) {
 | 
						|
				  	@text2( 0x161);
 | 
						|
					@text2( %$(eaddr->expr));
 | 
						|
				  }
 | 
						|
				  else {
 | 
						|
				  	@text2( 0x162);
 | 
						|
					@text2( %$(eaddr->expr));
 | 
						|
					@text2( %d(eaddr->expr2));
 | 
						|
				  }
 | 
						|
				  break;
 | 
						|
 | 
						|
	  case IS_IND_REG_DISPL : @text2( %$( eaddr->expr));
 | 
						|
				  break;
 | 
						|
 | 
						|
	  case IS_GLOB_LBL      : @reloc4( %$(eaddr->lbl),
 | 
						|
					   %$(eaddr->expr),
 | 
						|
					   ABSOLUTE);
 | 
						|
				  break;
 | 
						|
 | 
						|
	  case IS_3_OPS         : if ( isdigit( *(eaddr->expr)) &&
 | 
						|
				                    atoi( eaddr->expr) < 128) {
 | 
						|
 | 
						|
					@text2( %d( 0x0800 |
 | 
						|
				  	  	  ( eaddr->reg2 << 12) |
 | 
						|
					  	  ( two_log( eaddr->scale)<<9) |
 | 
						|
					  	  atoi( eaddr->expr)));
 | 
						|
				  }
 | 
						|
				  else
 | 
						|
					fprintf( stderr, "FOUT in IS_3_OPS\n");
 | 
						|
				  break;
 | 
						|
 | 
						|
	  case IS_QUICK		:
 | 
						|
	  case IS_IMMEDIATE	: if ( eaddr->lbl != NULL)
 | 
						|
					@reloc4( %$(eaddr->lbl),
 | 
						|
						 %$(eaddr->expr),
 | 
						|
						 ABSOLUTE);
 | 
						|
				  else
 | 
						|
					@text4( %$(eaddr->expr));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int reg_mode( eaddr)
 | 
						|
struct t_operand *eaddr;
 | 
						|
{
 | 
						|
	int mr;
 | 
						|
 | 
						|
	mr = mode_reg( eaddr);
 | 
						|
	return( ((mr & 0x7) << 3) | ((mr & 0x38) >> 3));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
code_opcode( opcode, field1, field2, eaddr)
 | 
						|
int opcode, field1, field2;
 | 
						|
struct t_operand *eaddr;
 | 
						|
{
 | 
						|
	@text2( %d(((opcode & 0xf) << 12) | ((field1 & 0x7) << 9) |
 | 
						|
		   ((field2 & 0x7) << 6) | (mode_reg(eaddr) & 0x3f)));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
code_instr( opcode, field1, field2, eaddr)
 | 
						|
int opcode, field1, field2;
 | 
						|
struct t_operand *eaddr;
 | 
						|
{
 | 
						|
	if (eaddr->type == IS_IND_REG_DISPL) {
 | 
						|
		@__instr_code(%d(((opcode & 0xf) << 12) | ((field1 & 0x7) << 9) |
 | 
						|
			        ((field2 & 0x7) << 6)),
 | 
						|
			      %d(eaddr->reg), %$(eaddr->expr));
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		code_opcode( opcode, field1, field2, eaddr);
 | 
						|
		code_extension( eaddr);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
code_move( size, src, dst)
 | 
						|
int size;
 | 
						|
struct t_operand *src, *dst;
 | 
						|
{
 | 
						|
	if (src->type == IS_IND_REG_DISPL) {
 | 
						|
		if (dst->type == IS_IND_REG_DISPL) {
 | 
						|
			@__moveXX(%d( ((size & 0x3) << 12)),
 | 
						|
				 %d(dst->reg), %$(dst->expr),
 | 
						|
				 %d(src->reg), %$(src->expr));
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			@__instr_code(%d( ((size & 0x3) << 12)|((reg_mode( dst) & 0x3f) << 6)),
 | 
						|
				 %d(src->reg), %$(src->expr));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (dst->type == IS_IND_REG_DISPL) {
 | 
						|
		@__move_X(%d( ((size & 0x3) << 12) | (mode_reg( src) & 0x3f)),
 | 
						|
			 %d(dst->reg), %$(dst->expr));
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		@text2( %d( ((size & 0x3) << 12) | ((reg_mode( dst) & 0x3f) << 6) |
 | 
						|
		    	     		   (mode_reg( src) & 0x3f)));
 | 
						|
		code_extension( src);
 | 
						|
		code_extension( dst);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
code_dist4( dst)
 | 
						|
struct t_operand *dst;
 | 
						|
{
 | 
						|
	@reloc4( %$(dst->lbl), %$(dst->expr) + 4, PC_REL);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int two_log( nr)
 | 
						|
register int nr;
 | 
						|
{
 | 
						|
	register int log;
 | 
						|
 | 
						|
	for ( log = 0; nr >= 2; nr >>= 1)
 | 
						|
		log++;
 | 
						|
 | 
						|
	return( log);
 | 
						|
}
 |