//
//	Copyright © 1997 Forest Edge Software, All Rights Reserved
//
//	Program:	VAX Emulator, a "Virtual VAX" for Mac OS Computers
//
//	Author:		Tom Cole
//
//	Module:		emul_test.c
//
//	Purpose:	Emulator handlers for integer test instructions
//
//				This single routine handles all integer test instructions.
//
//	History:	02/03/98	Created new routine
//
//


#include "vax.pch"

EMULATOR_ENTRY( emul_test )
{


	char * src1, *src2;
	
	long data, d1, d2;
	short dataw;
	char datab;
	unsigned long udata;
	unsigned char op, dsize, func;
	static long zero = 0L;
	
	data = 0L;
	udata = 0L;

	/*
	 	The instructions are structured like this:
	
		 1 0 0 1  0 0 1 1		BITB 
		 1 0 0 1  0 1 0 1		TSTB
	     1 0 1 1  0 0 1 1       BITW 
	     1 0 1 1  0 1 0 1       TSTW
	     1 1 0 1  0 0 1 1		BITL
	     1 1 0 1  0 1 0 1		TSTL
	     
		 
		So let's decompose the opcode to find out what the operations
		are that we'll do, and we can overload this routine with all
		the operations.
	 */

	op = opcode-> function;
	
	dsize = ( op >> 5 );		/*  4 = B, 5 = W, 6 = L */
	
	func  = ( op >> 1 ) & 0x03; /*  1 = BIT, 2 = TST	*/

	//	Get address of source data (from memory or from register).  Note
	//	that this might cause a page fault.  If so, then the get returns
	//	a null pointer.  In that case, return a fault return code.
	
	src1 = ( char * ) get_operand( vax, opcode, 0, OP_RD );
	if( src1 == 0L )
		return VAX_FAULT;
	
	if( func == 1 ) {
	
		src2 = ( char * ) get_operand( vax, opcode, 1, OP_RD );
		if( src2 == 0L )
			return VAX_FAULT;
	
	}
	else {
		src2 = ( char * ) &zero;
	}	
	
	
	/* Based on data size, we must manipulate right-sized variables */
	
	switch( dsize ) {
	
	case 4:	/* Byte */
	
		d1 = *(( char * ) src1 );	//	First operand
		d2 = *(( char * ) src2 );	//	Second operand
		
		switch( func ) {
		
		case 0:  data = d2 + d1; break;
		case 1:	 data = d2 - d1; break;
		case 2:  data = d2 * d1; break;
		case 3:  data = d2 / d1; break;
		
		case 4:	 data = d2 | d1; 		break;
		case 5:	 data = d2 & (~d1 );	break;
		
		}
		
		SETCONDITIONBITS( data, 0L );
		vax-> psl.bit.v = ( data > 255 ) || ( data < -256 );
		vax-> psl.bit.c = ( data & 0x00000100 ) >> 8;
		
		datab = ( char ) data;
		
		put_operand( vax, opcode, opcode->count - 1, OP_WR, ( char * ) &datab );
		break;
	
	case 5: /* Word */
			
		d1 = *(( short * ) src1 );
		d2 = *(( short * ) src2 );
		
		switch( func ) {
		
		case 0:  data = d1 + d2; break;
		case 1:	 data = d1 - d2; break;
		case 2:  data = d1 * d2; break;
		case 3:  data = d1 / d2; break;
		
		case 4:	 data = d2 | d1;		break;
		case 5:	 data = d2 & (~d1 );	break;
		
		}
		
		// If this is ADWC, add the carry bit back
		
		if( op == 0xD8 )
			data = data + vax-> psl.bit.c;
		
		SETCONDITIONBITS( data, 0L );
		vax-> psl.bit.v = ( data > 32767 ) || ( data < -32768 );
		vax-> psl.bit.c = ( data & 0x00010000 ) >> 16;
		
		dataw = ( short ) data;
		put_operand( vax, opcode, opcode->count - 1, OP_WR, ( char * ) &dataw );
		break;
	
	case 6: /* Longword */
	
	
	
		d1 = *(( long * ) src1 );
		d2 = *(( long * ) src2 );
		
		switch( func ) {
		
		case 0:  data = d1 + d2;
				 udata = ( unsigned long ) d1 + (unsigned long ) d2;
				 break;
				 
		case 1:  data = d1 - d2;
				 udata = ( unsigned long ) d1 - (unsigned long ) d2; 
				 break;
				 
		case 2:  data = d1 * d2; 
				 udata = ( unsigned long ) d1 * (unsigned long ) d2; 
				 break;
				 
		case 3:  data = d1 / d2; 
				 udata = ( unsigned long ) d1 / (unsigned long ) d2; 
				 break;
				 
		case 4:	 data = d2 | d1;
				 udata = ( unsigned long ) d2 | ( unsigned long ) d1 ;
				 break;
				 
		case 5:	 data = d2 & (~d1 );
				 udata = ( unsigned long ) d2 & ~(( unsigned long ) d1 );
				 break;
		}
		
		SETCONDITIONBITS( data, 0L );
		vax-> psl.bit.v = ( ( unsigned long ) data == udata ) ? 0 : 1;
		put_operand( vax, opcode, opcode->count - 1, OP_WR, ( char * ) &data );
		break;
	
	default:
	
		set_fault( vax, EXC_PRIV, 0 );
		return VAX_FAULT;
	
	}
	


	return VAX_OK;
}


