#include <stdio.h>
#include <allegro.h>

#include "structs.h"
#include "common.h"
#include "m68k.h"
#include "script.h"



inline void get_ccr_flags(){
	cc_x = (sr >> 4) & 1;
	cc_n = (sr >> 3) & 1;
	cc_z = (sr >> 2) & 1;
	cc_v = (sr >> 1) & 1;
	cc_c = sr & 1;
}

inline void store_ccr_flags(){
	sr &= 0xFFE0;
	sr += ((cc_x << 4) + (cc_n << 3) + (cc_z << 2) + (cc_v << 1) + cc_c);
}



int read_script(char s, char format){
	unsigned int value;
	//allegro_message("read_script");
	//allegro_message("s = %i", s);
	
	switch(s){
		case 1:
			value = obj_script[pc];
			pc++;
			break;
		case 2:
			value = obj_script[pc]
				+ (obj_script[pc+1] << 8);
			pc += 2;
			break;
		case 3:
			value = obj_script[pc]
				+ (obj_script[pc+1] << 8)
				+ (obj_script[pc+2] << 16);
			pc += 3;
			break;
		case 4:
			value = obj_script[pc]
				+ (obj_script[pc+1] << 8)
				+ (obj_script[pc+2] << 16)
				+ (obj_script[pc+3] << 24);
			pc += 4;
			break;
	}
			//allegro_message("value = %X", value);
	
	if(format == MOTOROLA)
		value = swap_endian(s, value);
			//allegro_message("value = %X", value);
	
	return value;
}



int swap_endian(char s, unsigned int v){
	if(s == 2)
		v = (((v >> 8) & 0xFF) + (v << 8)) & 0xFFFF;
	else if(s == 4){
		v = (v >> 24)
			+ ((v >> 8) & 0x0000FF00)
			+ ((v << 8) & 0x00FF0000)
			+ (v << 24);
	}
	
	return v;
}



int calc_effective_address(char s, char m, char r){
	int i;
	int index;
	int xn;
	//allegro_message("calc_effective_address");
	
	ea_big_endian = 0;
	
	switch(m){
		case 0:	// Dn
			ea = (int)&reg_d[r];
			break;
		case 1:	// An
			ea = (int)&reg_a[r];
			break;
		case 2:	// (An)
			ea = reg_a[r];
			if(!addr_literal){
				if(((ea >> 16) & 0xFF) == 0xFF)
					ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
				else
					ea += (int)obj_script;
			}
			break;
		case 3:	// (An)+
			ea = reg_a[r];
			if(r == 7){
				if(s == 4) reg_a[r] += 4;
				else reg_a[r] += 2;
			}
			else reg_a[r] += s;
			
			if(!addr_literal){
				if(((ea >> 16) & 0xFF) == 0xFF)
					ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
				else
					ea += (int)obj_script;
			}
			break;
		case 4:	// -(An)
			if(r == 7){
				if(s == 4) reg_a[r] -= 4;
				else reg_a[r] -= 2;
			}
			else reg_a[r] -= s;
			
			ea = reg_a[r];
			
			if(!addr_literal){
				if(((ea >> 16) & 0xFF) == 0xFF)
					ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
				else
					ea += (int)obj_script;
			}
			break;
		case 5:	// (D16, An)
			ea = reg_a[r] + read_script(2, MOTOROLA);
			
			if(!addr_literal){
				if(((ea >> 16) & 0xFF) == 0xFF)
					ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
				else
					ea += (int)obj_script;
			}
			break;
		case 6:	// (D8, An, Xn)
			ea = read_script(2, MOTOROLA);
			index = ea >> 8;
			
			if(index & 0x80)
				xn = reg_a[(index >> 4) & 7];
			else
				xn = reg_d[(index >> 4) & 7];
			
			if(index & 8)
				ea = (signed char)(ea & 0xFF) + reg_a[r] + xn;
			else
				ea = (signed char)(ea & 0xFF) + reg_a[r] + (signed short)xn;
			
			if(!addr_literal){
				if(((ea >> 16) & 0xFF) == 0xFF)
					ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
				else
					ea += (int)obj_script;
			}
			break;
		case 7:
			switch(r){
				case 0:	// (xxx).W
					ea = read_script(2, MOTOROLA);
					if(!addr_literal){
						if(ea & 0x8000){
							ea = ea | 0xFFFF0000;
							ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
						}
						else
							ea += (int)obj_script;
					}
					break;
				case 1:	// (xxx).L
					ea = read_script(4, MOTOROLA);
					if(!addr_literal){
						if(((ea >> 16) & 0xFF) == 0xFF)
							ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
						else
							ea += (int)obj_script;
					}
					break;
				case 2:	// (D16, PC)
					i = read_script(2, MOTOROLA);
					ea = pc + (short)i;
					if(!addr_literal){
						//if(((ea >> 16) & 0xFF) == 0xFF)
						//	ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
						//else
							ea += (int)obj_script;
					}
					break;
				case 3:	// (D8, PC, Xn)
					ea = read_script(2, MOTOROLA);
					i = ea & 0xFF;
					index = ea >> 8;
					
					if(index & 0x80)
						xn = reg_a[(index >> 4) & 7];
					else
						xn = reg_d[(index >> 4) & 7];
					
					if(index & 8)
						ea = (signed char)(ea & 0xFF) + pc-2 + xn;
					else
						ea = (signed char)(ea & 0xFF) + pc-2 + (signed short)xn;
					
					if(!addr_literal){
						//if(((ea >> 16) & 0xFF) == 0xFF)
						//	ea = (int)(&ram_68k) + 0xFFFF - (ea & 0xFFFF) - (s-1);
						//else
							ea += (int)obj_script;
						ea_big_endian = 1;
					}
					break;
				case 4:	// #imm
					if(s == 4)
						imm = read_script(4, MOTOROLA);
					else
						imm = read_script(2, MOTOROLA);
					ea = (int)&imm;
					break;
			}
	}
	
	addr_literal = 0;
	return 0;
}



void op_add(short data){
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Sm;
	int Dm;
	int Rm;
	
	unsigned int i;
	
	if(opmode == 3 || opmode == 7){
		#ifdef ENABLE_LOGGING
		WriteLog("ADDA");
		#endif
		calc_effective_address((opmode >> 1) + 1, ea_mode, ea_reg);
	}
	else{
		#ifdef ENABLE_LOGGING
		WriteLog("ADD");
		#endif
		calc_effective_address(1 << (opmode & 3), ea_mode, ea_reg);
	}
	
	if(opmode == 3 || opmode == 7){
		// ADDA
		switch(opmode){
			case 3:	// word
				i = reg_a[reg] & 0xFFFF;
				i += *(short *)ea;
				reg_a[reg] = (reg_a[reg] & 0xFFFF0000) + (unsigned short)i;
				break;
			case 7:	// long
				reg_a[reg] += *(int *)ea;
				break;
		}
	}
	else if(opmode & 4){
		// ADD
		switch(opmode & 3){
			case 0:
				Sm = reg_d[reg];
				Dm = *(char *)ea;
				i = *(char *)ea;
				i += reg_d[reg];
				*(char *)ea = (char)i;
				Rm = *(char *)ea;
				break;
			case 1:
				Sm = reg_d[reg];
				Dm = *(short *)ea;
				i = *(short *)ea;
				i += reg_d[reg];
				*(short *)ea = (short)i;
				Rm = *(short *)ea;
				break;
			case 2:
				Sm = reg_d[reg];
				Dm = *(short *)ea;
				*(int *)ea += reg_d[reg];
				Rm = *(int *)ea;
				break;
		}
	}
	else{
		// ADD
		switch(opmode & 3){
			case 0:
				Sm = *(char *)ea;
				Dm = (char)reg_d[reg];
				i = reg_d[reg] & 0xFF;
				i += *(char *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFFFF00) + (unsigned char)i;
				Rm = (char)reg_d[reg];
				break;
			case 1:
				Sm = *(short *)ea;
				Dm = (short)reg_d[reg];
				i = reg_d[reg] & 0xFFFF;
				i += *(short *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFF0000) + (unsigned short)i;
				Rm = (short)reg_d[reg];
				break;
			case 2:
				Sm = *(int *)ea;
				Dm = reg_d[reg];
				reg_d[reg] += *(int *)ea;
				Rm = reg_d[reg];
				break;
		}
	}
	
	if(!(opmode == 3 || opmode == 7)){
		get_ccr_flags();
		cc_n = (Rm < 0);
		cc_z = (Rm == 0);
		Sm >>= 31;
		Dm >>= 31;
		Rm >>= 31;
		cc_v = ((Sm && Dm && !Rm) || (!Sm && !Dm && Rm));
		cc_c = ((Sm && Dm) || (!Rm && Dm) || (Sm && !Rm));
		cc_x = cc_c;
		store_ccr_flags();
	}
}



void op_addi(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Sm;
	int Dm;
	int Rm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("ADDI");
	#endif
	
	calc_effective_address(1 << size, ea_mode, ea_reg);
	switch(size){
		case 0:
			Sm = (char)imm;
			Dm = *(char *)ea;
			imm = read_script(2, MOTOROLA);
			*(char *)ea += imm;
			Rm = *(char *)ea;
			break;
		case 1:
			Sm = (short)imm;
			Dm = *(short *)ea;
			imm = read_script(2, MOTOROLA);
			*(short *)ea += imm;
			Rm = *(short *)ea;
			break;
		case 2:
			Sm = imm;
			Dm = *(int *)ea;
			imm = read_script(4, MOTOROLA);
			*(int *)ea += imm;
			Rm = *(int *)ea;
			break;
	}
	
	get_ccr_flags();
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	Sm >>= 31;
	Dm >>= 31;
	Rm >>= 31;
	cc_v = ((Sm && Dm && !Rm) || (!Sm && !Dm && Rm));
	cc_c = ((Sm && Dm) || (!Rm && Dm) || (Sm && !Rm));
	cc_x = cc_c;
	store_ccr_flags();
}



void op_addq(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Sm;
	int Dm;
	int Rm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("ADDQ");
	#endif
	
	calc_effective_address(1 << size, ea_mode, ea_reg);
	switch(size){
		case 0:
			Sm = (char)imm;
			Dm = *(char *)ea;
			imm = (data >> 9) & 7;
			if(!imm) imm = 8;
			*(char *)ea += imm;
			Rm = *(char *)ea;
			break;
		case 1:
			Sm = (short)imm;
			Dm = *(short *)ea;
			imm = (data >> 9) & 7;
			if(!imm) imm = 8;
			*(short *)ea += imm;
			Rm = *(short *)ea;
			break;
		case 2:
			Sm = imm;
			Dm = *(int *)ea;
			imm = (data >> 9) & 7;
			if(!imm) imm = 8;
			*(int *)ea += imm;
			Rm = *(int *)ea;
			break;
	}
	
	get_ccr_flags();
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	Sm >>= 31;
	Dm >>= 31;
	Rm >>= 31;
	cc_v = ((Sm && Dm && !Rm) || (!Sm && !Dm && Rm));
	cc_c = ((Sm && Dm) || (!Rm && Dm) || (Sm && !Rm));
	cc_x = cc_c;
	store_ccr_flags();
}



void op_and(short data){
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("AND");
	#endif
	
	get_ccr_flags();
	calc_effective_address(1 << (opmode & 3), ea_mode, ea_reg);
	
	if(opmode & 4){
		switch(opmode & 3){
			case 0:
				i = *(char *)ea;
				i &= reg_d[reg];
				*(char *)ea = (char)i;
				
				cc_n = (i >> 7) & 1;
				
				break;
			case 1:
				i = *(short *)ea;
				i &= reg_d[reg];
				*(short *)ea = (short)i;
				
				cc_n = (i >> 15) & 1;
				
				break;
			case 2:
				*(int *)ea &= reg_d[reg];
				
				cc_n = (i >> 31) & 1;	
				
				break;
		}
	}
	else{
		switch(opmode & 3){
			case 0:
				i = reg_d[reg] & 0xFF;
				i &= *(char *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFFFF00) + (unsigned char)i;
				
				cc_n = (reg_d[reg] >> 7) & 1;
				
				break;
			case 1:
				i = reg_d[reg] & 0xFFFF;
				i &= *(short *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFF0000) + (unsigned short)i;
				
				cc_n = (reg_d[reg] >> 15) & 1;
				
				break;
			case 2:
				reg_d[reg] &= *(int *)ea;
				
				cc_n = reg_d[reg] >> 31;
				
				break;
		}
	}
	
	cc_z = (i == 0);
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_andi(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("ANDI");
	#endif
	
	if(data == 0x23C){
		imm = read_script(2, MOTOROLA);
		ea = (int)&sr;
		*(char *)ea &= imm;
		return;
	}
	if(data == 0x27C){
		imm = read_script(2, MOTOROLA);
		ea = (int)&sr;
		*(short *)ea &= imm;
		return;
	}
	
	get_ccr_flags();
	
	calc_effective_address(1 << size, ea_mode, ea_reg);
	switch(size){
		case 0:
			imm = read_script(2, MOTOROLA);
			*(char *)ea &= imm;
			cc_n = ((*(char *)ea & 0x80) != 0);
			cc_z = (*(char *)ea == 0);
			break;
		case 1:
			imm = read_script(2, MOTOROLA);
			*(short *)ea &= imm;
			cc_n = ((*(short *)ea & 0x8000) != 0);
			cc_z = (*(short *)ea == 0);
			break;
		case 2:
			imm = read_script(4, MOTOROLA);
			*(int *)ea &= imm;
			cc_n = ((*(int *)ea & 0x80000000) != 0);
			cc_z = (*(int *)ea == 0);
			break;
	}
	
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_bcc(short data){
	char condition = (data >> 8) & 0xF;
	int displacement = data & 0xFF;
	char result;
	
	get_ccr_flags();
	
	switch(condition){
		case 0:
			#ifdef ENABLE_LOGGING
			WriteLog("BRA");
			#endif
			result = 1;
			break;
		case 1:
			#ifdef ENABLE_LOGGING
			WriteLog("BSR");
			#endif
			result = 1;
			break;
		case 2:
			#ifdef ENABLE_LOGGING
			WriteLog("BHI");
			#endif
			result = (!cc_c && !cc_z);
			break;
		case 3:
			#ifdef ENABLE_LOGGING
			WriteLog("BLS");
			#endif
			result = (cc_c || cc_z);
			break;
		case 4:
			#ifdef ENABLE_LOGGING
			WriteLog("BCC");
			#endif
			result = (!cc_c);
			break;
		case 5:
			#ifdef ENABLE_LOGGING
			WriteLog("BCS");
			#endif
			result = cc_c;
			break;
		case 6:
			#ifdef ENABLE_LOGGING
			WriteLog("BNE");
			#endif
			result = (!cc_z);
			break;
		case 7:
			#ifdef ENABLE_LOGGING
			WriteLog("BEQ");
			#endif
			result = cc_z;
			break;
		case 8:
			#ifdef ENABLE_LOGGING
			WriteLog("BVC");
			#endif
			result = (!cc_v);
			break;
		case 9:
			#ifdef ENABLE_LOGGING
			WriteLog("BVS");
			#endif
			result = cc_v;
			break;
		case 10:
			#ifdef ENABLE_LOGGING
			WriteLog("BPL");
			#endif
			result = (!cc_n);
			break;
		case 11:
			#ifdef ENABLE_LOGGING
			WriteLog("BMI");
			#endif
			result = cc_n;
			break;
		case 12:
			#ifdef ENABLE_LOGGING
			WriteLog("BGE");
			#endif
			result = ((cc_n && cc_v) || (!cc_n && !cc_v));
			break;
		case 13:
			#ifdef ENABLE_LOGGING
			WriteLog("BLT");
			#endif
			result = ((cc_n && !cc_v) || (!cc_n && cc_v));
			break;
		case 14:
			#ifdef ENABLE_LOGGING
			WriteLog("BGT");
			#endif
			result = ((cc_n && cc_v && !cc_z) || (!cc_n && !cc_v && !cc_z));
			break;
		case 15:
			#ifdef ENABLE_LOGGING
			WriteLog("BLE");
			#endif
			result = (cc_z || (cc_n && !cc_v) || (!cc_n && cc_v));
			break;
	}
	
	/*if(pc >= 0x7E && pc <= 0x82){
		allegro_message("%X", cc_z);
		rest(35);
	}*/
	
	if(condition == 1){		// BSR
		reg_a[7] -= 4;
		*(int *)(&ram_68k[reg_a[7] & 0xFFFF]) = pc;
		
		if(displacement == 0)
			*(int *)(&ram_68k[reg_a[7] & 0xFFFF]) += 2;
	}
	
	if(displacement == 0){			// 16-bit
		displacement = read_script(2, MOTOROLA) - 2;
		//pc -= 2;
		if(displacement & 0x8000)
			displacement |= 0xFFFF8000;
	}
	//else if(displacement == 0xFF)	// 32-bit
	//	displacement = read_script(4, MOTOROLA);
	else if(displacement & 0x80){	// 8-bit
		displacement |= 0xFFFFFF80;
		//pc -= 2;
	}
	
	if(result)		
		pc += (displacement/* - 2*/);
	//else if(displacement == 0)
	//	pc += 2;
}



void op_bchg(short data){
	char size;
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("BCHG");
	#endif
	
	if(ea_mode == 0)
		size = 4;
	else
		size = 1;
	
	get_ccr_flags();
	
	if(opmode == 5){
		calc_effective_address(size, ea_mode, ea_reg);
		switch(size){
			case 1:
				i = *(char *)ea;
				cc_z = ((i & (1 << (reg_d[reg] % 8))) == 0);
				i ^= (1 << (reg_d[reg] % 8));
				*(char *)ea = (char)i;
				break;
			case 4:
				i = *(int *)ea;
				cc_z = ((i & (1 << (reg_d[reg] % 32))) == 0);
				i ^= (1 << (reg_d[reg] % 32));
				*(int *)ea = (int)i;
				break;
		}
	}
	else{
		switch(size){
			case 1:
				imm = read_script(2, MOTOROLA);
				calc_effective_address(size, ea_mode, ea_reg);
				i = *(int *)ea;
				cc_z = ((i & (1 << (imm % 8))) == 0);
				i ^= (1 << (imm % 8));
				*(char *)ea = (char)i;
				break;
			case 4:
				imm = read_script(2, MOTOROLA);
				calc_effective_address(size, ea_mode, ea_reg);
				i = *(int *)ea;
				cc_z = ((i & (1 << (imm % 32))) == 0);
				i ^= (1 << (imm % 32));
				*(int *)ea = (int)i;
				break;
		}
	}
	
	store_ccr_flags();
}



void op_bclr(short data){
	char size;
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("BCLR");
	#endif
	
	if(ea_mode == 0)
		size = 4;
	else
		size = 1;
	
	get_ccr_flags();
	
	if(opmode == 6){
		calc_effective_address(size, ea_mode, ea_reg);
		switch(size){
			case 1:
				i = *(char *)ea;
				cc_z = ((i & (1 << (reg_d[reg] % 8))) == 0);
				i = ~((~i) | (1 << (reg_d[reg] % 8)));
				*(char *)ea = (char)i;
				break;
			case 4:
				i = *(int *)ea;
				cc_z = ((i & (1 << (reg_d[reg] % 32))) == 0);
				i = ~((~i) | (1 << (reg_d[reg] % 32)));
				*(int *)ea = (int)i;
				break;
		}
	}
	else{
		switch(size){
			case 1:
				imm = read_script(2, MOTOROLA);
				calc_effective_address(size, ea_mode, ea_reg);
				i = *(char *)ea;
				cc_z = ((i & (1 << (imm % 8))) == 0);
				i = ~((~i) | (1 << (imm % 8)));
				*(char *)ea = (char)i;
				break;
			case 4:
				imm = read_script(2, MOTOROLA);
				calc_effective_address(size, ea_mode, ea_reg);
				i = *(int *)ea;
				cc_z = ((i & (1 << (imm % 32))) == 0);
				i = ~((~i) | (1 << (imm % 32)));
				*(int *)ea = (int)i;
				break;
		}
	}
	
	store_ccr_flags();
}



void op_bset(short data){
	char size;
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("BSET");
	#endif
	
	if(ea_mode == 0)
		size = 4;
	else
		size = 1;
	
	get_ccr_flags();
	
	if(opmode == 7){
		calc_effective_address(size, ea_mode, ea_reg);
		switch(size){
			case 1:
				i = *(char *)ea;
				cc_z = ((i & (1 << (reg_d[reg] % 8))) == 0);
				i |= (1 << (reg_d[reg] % 8));
				*(char *)ea = (char)i;
				break;
			case 4:
				i = *(int *)ea;
				cc_z = ((i & (1 << (reg_d[reg] % 32))) == 0);
				i |= (1 << (reg_d[reg] % 32));
				*(int *)ea = (int)i;
				break;
		}
	}
	else{
		switch(size){
			case 1:
				imm = read_script(2, MOTOROLA);
				calc_effective_address(size, ea_mode, ea_reg);
				i = *(int *)ea;
				cc_z = ((i & (1 << (imm % 8))) == 0);
				i |= (1 << (imm % 8));
				*(char *)ea = (char)i;
				break;
			case 4:
				imm = read_script(2, MOTOROLA);
				calc_effective_address(size, ea_mode, ea_reg);
				i = *(int *)ea;
				cc_z = ((i & (1 << (imm % 32))) == 0);
				i |= (1 << (imm % 32));
				*(int *)ea = (int)i;
				break;
		}
	}
	
	store_ccr_flags();
}



void op_btst(short data){
	char size;						// 1
	char reg = (data >> 9) & 7;		// 4
	char opmode = (data >> 6) & 7;	// 0
	char ea_mode = (data >> 3) & 7;	// 5
	char ea_reg = data & 7;			// 0
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("BTST");
	#endif
	
	if(ea_mode == 0)
		size = 4;
	else
		size = 1;
	
	get_ccr_flags();
	
	if(opmode == 4){
		calc_effective_address(size, ea_mode, ea_reg);
		switch(size){
			case 1:
				i = *(char *)ea;
				i >>= (reg_d[reg] % 8);
				cc_z = (i & 1) ^ 1;
				break;
			case 4:
				i = *(int *)ea;
				i >>= (reg_d[reg] % 32);
				cc_z = (i & 1) ^ 1;
				break;
		}
	}
	else{
		switch(size){
			case 1:
				imm = read_script(2, MOTOROLA);
				calc_effective_address(size, ea_mode, ea_reg);
				i = *(int *)ea;
				i >>= (imm % 8);
				cc_z = (i & 1) ^ 1;
				break;
			case 4:
				imm = read_script(2, MOTOROLA);
				calc_effective_address(size, ea_mode, ea_reg);
				i = *(int *)ea;
				i >>= (imm % 32);
				cc_z = (i & 1) ^ 1;
				break;
		}
	}
	
	store_ccr_flags();
}



void op_clr(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("CLR");
	#endif
	
	calc_effective_address(1 << size, ea_mode, ea_reg);
	switch(size){
		case 0:
			*(char *)ea = 0;
			break;
		case 1:
			*(short *)ea = 0;
			break;
		case 2:
			*(int *)ea = 0;
			break;
	}
	
	get_ccr_flags();
	cc_n = 0;
	cc_z = 1;
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_cmp(short data){
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	int Rm;
	int Dm;
	int Sm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	if(opmode < 3)
		WriteLog("CMP");
	else
		WriteLog("CMPA");
	#endif
	
	calc_effective_address(1 << (opmode & 3), ea_mode, ea_reg);
	
	switch(opmode & 7){
		case 0:
			Rm = (char)reg_d[reg] - *(char *)ea;
			Dm = (char)reg_d[reg];
			Sm = *(char *)ea;
			//if(Sm & 0x80)
			//	Sm |= 0xFFFFFF80;
			break;
		case 1:
			Rm = (short)reg_d[reg] - *(short *)ea;
			Dm = (short)reg_d[reg];
			Sm = *(short *)ea;
			//if(Sm & 0x8000)
			//	Sm |= 0xFFFF8000;
			break;
		case 2:
			Rm = reg_d[reg] - *(int *)ea;
			Dm = reg_d[reg];
			Sm = *(int *)ea;
			break;
		case 3:
			Rm = (short)reg_a[reg] - *(short *)ea;
			Dm = (short)reg_a[reg];
			Sm = *(short *)ea;
			break;
		case 7:
			Rm = reg_a[reg] - *(int *)ea;
			Dm = reg_a[reg];
			Sm = *(int *)ea;
			break;
	}
	
	get_ccr_flags();
	
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	Sm >>= 31;
	Dm >>= 31;
	Rm >>= 31;
	cc_v = ((!Sm && Dm && !Rm) || (Sm && !Dm && Rm));
	cc_c = ((Sm && !Dm) || (Rm && !Dm) || (Sm && Rm));
	
	store_ccr_flags();
}



void op_cmpi(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	int Rm;
	int Dm;
	int Sm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("CMPI");
	#endif
	
	switch(size){
		case 0:
			imm = read_script(2, MOTOROLA);
			calc_effective_address(1 << size, ea_mode, ea_reg);
			Rm = *(char *)ea - (char)imm;
			Dm = *(char *)ea;
			Sm = (char)imm;
			//if(Sm & 0x80)
			//	Sm |= 0xFFFFFF80;
			break;
		case 1:
			imm = read_script(2, MOTOROLA);
			calc_effective_address(1 << size, ea_mode, ea_reg);
			Rm = *(short *)ea - (short)imm;
			Dm = *(short *)ea;
			Sm = (short)imm;
			//if(Sm & 0x8000)
			//	Sm |= 0xFFFF8000;
			break;
		case 2:
			imm = read_script(4, MOTOROLA);
			calc_effective_address(1 << size, ea_mode, ea_reg);
			Rm = *(int *)ea - imm;
			Dm = *(int *)ea;
			Sm = imm;
			break;
	}
	
	get_ccr_flags();
	
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	Sm >>= 31;
	Dm >>= 31;
	Rm >>= 31;
	cc_v = ((!Sm && Dm && !Rm) || (Sm && !Dm && Rm));
	cc_c = ((Sm && !Dm) || (Rm && !Dm) || (Sm && Rm));
	
	store_ccr_flags();
}



void op_dbcc(short data){
	char condition = (data >> 8) & 0xF;
	int reg = data & 7;
	short displacement;
	char result;
	
	get_ccr_flags();
	
	displacement = read_script(2, MOTOROLA);
	
	switch(condition){
		case 0:
			#ifdef ENABLE_LOGGING
			WriteLog("DBT");
			#endif
			return;
			//break;
		case 1:
			#ifdef ENABLE_LOGGING
			WriteLog("DBF");
			#endif
			if((short)reg_d[reg])
				result = 0;
			else
				result = 1;
			break;
		case 2:
			#ifdef ENABLE_LOGGING
			WriteLog("DBHI");
			#endif
			result = (!cc_c && !cc_z);
			break;
		case 3:
			#ifdef ENABLE_LOGGING
			WriteLog("DBLS");
			#endif
			result = (cc_c || cc_z);
			break;
		case 4:
			#ifdef ENABLE_LOGGING
			WriteLog("DBCC");
			#endif
			result = (!cc_c);
			break;
		case 5:
			#ifdef ENABLE_LOGGING
			WriteLog("DBCS");
			#endif
			result = cc_c;
			break;
		case 6:
			#ifdef ENABLE_LOGGING
			WriteLog("DBNE");
			#endif
			result = (!cc_z);
			break;
		case 7:
			#ifdef ENABLE_LOGGING
			WriteLog("DBEQ");
			#endif
			result = cc_z;
			break;
		case 8:
			#ifdef ENABLE_LOGGING
			WriteLog("DBVC");
			#endif
			result = (!cc_v);
			break;
		case 9:
			#ifdef ENABLE_LOGGING
			WriteLog("DBVS");
			#endif
			result = cc_v;
			break;
		case 10:
			#ifdef ENABLE_LOGGING
			WriteLog("DBPL");
			#endif
			result = (!cc_n);
			break;
		case 11:
			#ifdef ENABLE_LOGGING
			WriteLog("DBMI");
			#endif
			result = cc_n;
			break;
		case 12:
			#ifdef ENABLE_LOGGING
			WriteLog("DBGE");
			#endif
			result = ((cc_n && cc_v) || (!cc_n && !cc_v));
			break;
		case 13:
			#ifdef ENABLE_LOGGING
			WriteLog("DBLT");
			#endif
			result = ((cc_n && !cc_v) || (!cc_n && cc_v));
			break;
		case 14:
			#ifdef ENABLE_LOGGING
			WriteLog("DBGT");
			#endif
			result = ((cc_n && cc_v && !cc_z) || (!cc_n && !cc_v && !cc_z));
			break;
		case 15:
			#ifdef ENABLE_LOGGING
			WriteLog("DBLE");
			#endif
			result = (cc_z || (cc_n && !cc_v) || (!cc_n && cc_v));
			break;
	}
	
	/*if(pc >= 0x7E && pc <= 0x82){
		allegro_message("%X", cc_z);
		rest(35);
	}*/
	
	if(!result){
		(*(short *)(&reg_d[reg]))--;
		if((*(short *)(&reg_d[reg])) != -1)
			pc += (displacement - 2);
	}
}



void op_eor(short data){
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("EOR");
	#endif
	
	get_ccr_flags();
	calc_effective_address(1 << (opmode & 3), ea_mode, ea_reg);
	
	if(opmode & 4){
		switch(opmode & 3){
			case 0:
				i = *(char *)ea;
				i ^= reg_d[reg];
				*(char *)ea = (char)i;
				cc_n = ((*(char *)ea & 0x80) != 0);
				cc_z = (*(char *)ea == 0);
				cc_v = 0;
				cc_c = 0;
				break;
			case 1:
				i = *(short *)ea;
				i ^= reg_d[reg];
				*(short *)ea = (short)i;
				cc_n = ((*(short *)ea & 0x8000) != 0);
				cc_z = (*(short *)ea == 0);
				cc_v = 0;
				cc_c = 0;
				break;
			case 2:
				*(int *)ea ^= reg_d[reg];
				cc_n = ((*(int *)ea & 0x80000000) != 0);
				cc_z = (*(int *)ea == 0);
				cc_v = 0;
				cc_c = 0;
				break;
		}
	}
	else{
		switch(opmode & 3){
			case 0:
				i = reg_d[reg] & 0xFF;
				i ^= *(char *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFFFF00) + (unsigned char)i;
				cc_n = ((reg_d[reg] & 0x80) != 0);
				cc_z = ((char)reg_d[reg] == 0);
				cc_v = 0;
				cc_c = 0;
				break;
			case 1:
				i = reg_d[reg] & 0xFFFF;
				i ^= *(short *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFF0000) + (unsigned short)i;
				cc_n = ((reg_d[reg] & 0x8000) != 0);
				cc_z = ((short)reg_d[reg] == 0);
				cc_v = 0;
				cc_c = 0;
				break;
			case 2:
				reg_d[reg] ^= *(int *)ea;
				cc_n = ((reg_d[reg] & 0x80000000) != 0);
				cc_z = ((int)reg_d[reg] == 0);
				cc_v = 0;
				cc_c = 0;
				break;
		}
	}
	
	store_ccr_flags();
}



void op_eori(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("EORI");
	#endif
	
	if(data == 0xA3C){
		imm = read_script(2, MOTOROLA);
		ea = (int)&sr;
		*(char *)ea ^= imm;
		return;
	}
	if(data == 0xA7C){
		imm = read_script(2, MOTOROLA);
		ea = (int)&sr;
		*(short *)ea ^= imm;
		return;
	}
	
	get_ccr_flags();
	
	calc_effective_address(1 << size, ea_mode, ea_reg);
	switch(size){
		case 0:
			imm = read_script(2, MOTOROLA);
			*(char *)ea ^= imm;
			cc_n = ((*(char *)ea & 0x80) != 0);
			cc_z = (*(char *)ea == 0);
			cc_v = 0;
			cc_c = 0;
			break;
		case 1:
			imm = read_script(2, MOTOROLA);
			*(short *)ea ^= imm;
			cc_n = ((*(short *)ea & 0x8000) != 0);
			cc_z = (*(short *)ea == 0);
			cc_v = 0;
			cc_c = 0;
			break;
		case 2:
			imm = read_script(4, MOTOROLA);
			*(int *)ea ^= imm;
			cc_n = ((*(int *)ea & 0x80000000) != 0);
			cc_z = (*(int *)ea == 0);
			cc_v = 0;
			cc_c = 0;
			break;
	}
	
	store_ccr_flags();
}



void op_ext(short data){
	char opmode = (data >> 6) & 7;	// size
	char reg = data & 7;
	char signbit;
	
	#ifdef ENABLE_LOGGING
	WriteLog("EXT");
	#endif
	
	get_ccr_flags();
	
	switch(opmode){
		case 2:	// byte -> word
			signbit = (reg_d[reg] >> 7) & 1;
			if(signbit)
				reg_d[reg] |= 0xFF00;
			else
				reg_d[reg] &= 0xFFFF00FF;
			cc_n = ((short)reg_d[reg] < 0);
			cc_z = ((short)reg_d[reg] == 0);
			break;
		case 3:	// word -> long
			signbit = (reg_d[reg] >> 15) & 1;
			if(signbit)
				reg_d[reg] |= 0xFFFF0000;
			else
				reg_d[reg] &= 0xFFFF;
			cc_n = (reg_d[reg] < 0);
			cc_z = (reg_d[reg] == 0);
			break;
	}
	
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_jmp(short data){
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	calc_effective_address(4, ea_mode, ea_reg);
	
	if((data & 0xC0) == 0x80){
		#ifdef ENABLE_LOGGING
		WriteLog("JSR");
		#endif
		//reg_a[7]--;
		//ram_68k[reg_a[7] & 0xFFFF] = pc;
		reg_a[7] -= 4;
		*(int *)(&ram_68k[reg_a[7] & 0xFFFF]) = pc;
	}
	#ifdef ENABLE_LOGGING
	else
		WriteLog("JMP");
	#endif
	
	pc = ea;
	ea = (int)obj_script;
	pc -= ea;
}



void op_lea(short data){
	char reg = (data >> 9) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	#ifdef ENABLE_LOGGING
	WriteLog("LEA");
	#endif
	
	addr_literal = 1;
	calc_effective_address(4, ea_mode, ea_reg);
	
	if(ea_mode == 7 && ea_reg == 0){
		if(ea & 0x8000)
			ea |= 0xFFFF8000;
	}
	
	reg_a[reg] = ea;
	//reg_a[reg] = swap_endian(4, reg_a[reg]);
}



void op_lsd(short data){
	char count = (data >> 9) & 7;	// 4
	char dr = (data >> 8) & 1;		// 0
	char size = (data >> 6) & 3;	// 1
	char ir = (data >> 5) & 1;		// 0
	char mode = (data >> 3) & 7;	// 0
	char reg = data & 7;			// 1
	
	char arithmetic = 0;
	
	if(dr){
		#ifdef ENABLE_LOGGING
		if(size == 3){
			if(count & 1)
				WriteLog("LSL");
			else
				WriteLog("ASL");
		}
		else if(mode & 1)
			WriteLog("LSL");
		else
			WriteLog("ASL");
		#endif
	}
	else{
		if(size == 3){
			if(count & 1){
				#ifdef ENABLE_LOGGING
				WriteLog("LSR");
				#endif
			}
			else{
				arithmetic = 1;
				#ifdef ENABLE_LOGGING
				WriteLog("ASR");
				#endif
			}
		}
		else if(mode & 1){
			#ifdef ENABLE_LOGGING
			WriteLog("LSR");
			#endif
		}
		else{
			arithmetic = 1;
			#ifdef ENABLE_LOGGING
			WriteLog("ASR");
			#endif
		}
	}
	
	if(size != 3){ // Destination is a register
		if(dr){ // LEFT SHIFT
			switch(size){
				case 0:
					ea = (int)&reg_d[reg];
					//ea += 3;
					if(ir)
						*(char *)ea <<= (reg_d[count] % 64);
					else
						*(char *)ea <<= count;
					break;
				case 1:
					ea = (int)&reg_d[reg];
					//ea += 2;
					if(ir)
						*(short *)ea <<= (reg_d[count] % 64);
					else
						*(short *)ea <<= count;
					break;
				case 2:
					if(ir)
						reg_d[reg] <<= (reg_d[count] % 64);
					else
						reg_d[reg] <<= count;
					break;
			}
		}
		else{ // RIGHT SHIFT
			switch(size){
				case 0:
					ea = (int)&reg_d[reg];
					//ea += 3;
					if((*(char *)ea) & 0x80 && arithmetic){
						if(ir){
							*(char *)ea >>= (reg_d[count] % 64);
							*(char *)ea |= ((0xFF << (8 - (reg_d[count] % 64))) & 0xFF);
						}
						else{
							*(char *)ea >>= count;
							*(char *)ea |= ((0xFF << (8 - count)) & 0xFF);
						}
					}
					else{
						if(ir)
							*(char *)ea >>= (reg_d[count] % 64);
						else
							*(char *)ea >>= count;
					}
					break;
				case 1:
					ea = (int)&reg_d[reg];
					//ea += 2;
					if((*(short *)ea) >> 15 && arithmetic){
						if(ir){
							*(short *)ea >>= (reg_d[count] % 64);
							*(short *)ea |= ((0xFFFF << (16 - (reg_d[count] % 64))) & 0xFFFF);
						}
						else{
							*(short *)ea >>= count;
							*(short *)ea |= ((0xFF00 << (8 - count)) & 0xFF00);
						}
					}
					else{
						if(ir)
							*(short *)ea >>= (reg_d[count] % 64);
						else
							*(short *)ea >>= count;
					}
					break;
				case 2:
					if(reg_d[reg] & 0x80000000 && arithmetic){
						if(ir){
							reg_d[reg] >>= (reg_d[count] % 64);
							reg_d[reg] |= ((0xFFFFFFFF << (32 - (reg_d[count] % 64))) & 0xFFFFFFFF);
						}
						else{
							reg_d[reg] >>= count;
							reg_d[reg] |= ((0xFF000000 << (8 - count)) & 0xFF000000);
						}
					}
					else{
						if(ir)
							reg_d[reg] >>= (reg_d[count] % 64);
						else
							reg_d[reg] >>= count;
					}
					break;
			}
		}
	}
	else{ // Destination is <EA>
		if(dr){ // LEFT SHIFT
			calc_effective_address(2, mode, reg);
			*(short *)ea <<= count;
		}
		else if((*(short *)ea) & 0x8000 && arithmetic){ // RIGHT SHIFT (arithmetic)
			calc_effective_address(2, mode, reg);
			*(short *)ea >>= count;
			*(short *)ea |= ((0xFF00 << (8 - count)) & 0xFF00);
		}
		else{ // RIGHT SHIFT (logical)
			calc_effective_address(2, mode, reg);
			*(short *)ea >>= count;
		}
	}
}



void op_move(short data){
	char size = (data >> 12) & 3;
	char dest_reg = (data >> 9) & 7;
	char dest_mode = (data >> 6) & 7;
	char src_mode = (data >> 3) & 7;
	char src_reg = data & 7;
	
	int Rm;
	
	int *dest;
	int *src;
	char dest_big_endian;
	
	unsigned int i;
	
	if(size == 3)
		size = 2;
	else if(size == 2)
		size = 4;
	
	#ifdef ENABLE_LOGGING
	if(dest_mode == 1)
		WriteLog("MOVEA");
	else
		WriteLog("MOVE");
	#endif
	
	calc_effective_address(size, src_mode, src_reg);
	src = (int *)ea;
	dest_big_endian = ea_big_endian;
	calc_effective_address(size, dest_mode, dest_reg);
	dest = (int *)ea;
	
	ea_big_endian ^= dest_big_endian;
	
	switch(size){
		case 1:
			*(char *)dest = *(char *)src;
			Rm = *(char *)src;
			break;
		case 2:
			*(short *)dest = *(short *)src;
			if(ea_big_endian)
				*(short *)dest = swap_endian(2, *(short *)dest);
			Rm = *(short *)src;
			break;
		case 4:
			*dest = *src;
			if(ea_big_endian)
				*dest = swap_endian(4, *dest);
			Rm = *src;
			break;
	}
	
	if(dest_mode != 1){
		get_ccr_flags();
		cc_n = (Rm < 0);
		cc_z = (Rm == 0);
		cc_v = 0;
		cc_c = 0;
		store_ccr_flags();
	}
}



void op_movem(short data){
	char dr = (data >> 10) & 1;
	char size = (data >> 6) & 1;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	short mask = read_script(2, MOTOROLA);
	
	int i;
	//allegro_message("%X\n%X\n%X", 2 << size, ea_mode, ea_reg);
	#ifdef ENABLE_LOGGING
	WriteLog("MOVEM");
	#endif
	
	if(dr){ // Memory -> Registers
		if(ea_mode != 4){ // A7 is bit 15, D0 is bit 0
			for(i=0; i < 8; i++){
				if((mask >> i) & 1){
					calc_effective_address(2 << size, ea_mode, ea_reg);
					if(size == 0)	reg_d[i] = *(short *)ea;
					else			reg_d[i] = *(int *)ea;
					//allegro_message("A1\n\nea = %X\na7 = %X\nREG = %X", ea, reg_a[7], i);
				}
			}
			for(i=0; i < 8; i++){
				if((mask >> (i+8)) & 1){
					calc_effective_address(2 << size, ea_mode, ea_reg);
					if(size == 0)	reg_a[i] = *(short *)ea;
					else			reg_a[i] = *(int *)ea;
					//allegro_message("A2\n\nea = %X\na7 = %X\nREG = %X", ea, reg_a[7], i);
				}
			}
		}
		else{ // D0 is bit 15, A7 is bit 0
			for(i=0; i < 8; i++){
				if((mask >> i) & 1){
					calc_effective_address(2 << size, ea_mode, ea_reg);
					if(size == 0)	reg_a[7-i] = *(short *)ea;
					else			reg_a[7-i] = *(int *)ea;
					//allegro_message("A3\n\nea = %X\na7 = %X\nREG = %X", ea, reg_a[7], 7-i);
				}
			}
			for(i=0; i < 8; i++){
				if((mask >> (i+8)) & 1){
					calc_effective_address(2 << size, ea_mode, ea_reg);
					if(size == 0)	reg_d[7-i] = *(short *)ea;
					else			reg_d[7-i] = *(int *)ea;
					//allegro_message("A4\n\nea = %X\na7 = %X\nREG = %X", ea, reg_a[7], 7-i);
				}
			}
		}
	}
	else{ // Registers -> Memory
		if(ea_mode != 4){ // A7 is bit 15, D0 is bit 0
			for(i=0; i < 8; i++){
				if((mask >> i) & 1){
					calc_effective_address(2 << size, ea_mode, ea_reg);
					if(size == 0)	*(short *)ea = reg_d[i];
					else			*(int *)ea = reg_d[i];
					//allegro_message("B1\n\nea = %X\na7 = %X\nREG = %X", ea, reg_a[7], i);
				}
			}
			for(i=0; i < 8; i++){
				if((mask >> (i+8)) & 1){
					calc_effective_address(2 << size, ea_mode, ea_reg);
					if(size == 0)	*(short *)ea = reg_a[i];
					else			*(int *)ea = reg_a[i];
					//allegro_message("B2\n\nea = %X\na7 = %X\nREG = %X", ea, reg_a[7], i);
				}
			}
		}
		else{ // D0 is bit 15, A7 is bit 0
			for(i=0; i < 8; i++){
				if((mask >> i) & 1){
					calc_effective_address(2 << size, ea_mode, ea_reg);
					if(size == 0)	*(short *)ea = reg_a[7-i];
					else 			*(int *)ea = reg_a[7-i];
					//allegro_message("B3\n\nea = %X\na7 = %X\nREG = %X", ea, reg_a[7], 7-i);
				}
			}
			for(i=0; i < 8; i++){
				if((mask >> (i+8)) & 1){
					calc_effective_address(2 << size, ea_mode, ea_reg);
					if(size == 0)	*(short *)ea = reg_d[7-i];
					else			*(int *)ea = reg_d[7-i];
					//allegro_message("B4\n\nea = %X\na7 = %X\nREG = %X", ea, reg_a[7], 7-i);
				}
			}
		}
	}
}



void op_moveq(short data){
	char reg = (data >> 9) & 7;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("MOVEQ");
	#endif
	
	i = data & 0xFF;
	if(data & 0x80)
		i |= 0xFFFFFF00;
	
	reg_d[reg] = i;
	
	get_ccr_flags();
	cc_n = (reg_d[reg] < 0);
	cc_z = (reg_d[reg] == 0);
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_muls(short data){
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Sm;
	int Dm;
	int Rm;
	
	unsigned int i;
	
	if(opmode == 3){
		#ifdef ENABLE_LOGGING
		WriteLog("MULU");
		#endif
		calc_effective_address(2, ea_mode, ea_reg);
	}
	else{
		#ifdef ENABLE_LOGGING
		WriteLog("MULS");
		#endif
		calc_effective_address(2, ea_mode, ea_reg);
	}
	
	if(opmode == 3){
		// MULU
		Sm = *(unsigned short *)ea;
		Dm = reg_d[reg] & 0xFFFF;
		Rm = Sm * Dm;
		reg_d[reg] = Rm;
	}
	else{
		// MULS
		Sm = *(short *)ea;
		Dm = (short)reg_d[reg];
		Rm = Sm * Dm;
		reg_d[reg] = Rm;
	}
	
	get_ccr_flags();
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_neg(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Dm;
	int Rm;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("NEG");
	#endif
	
	get_ccr_flags();
	calc_effective_address(1 << size, ea_mode, ea_reg);
	
	switch(size){
		case 0:
			Dm = (*(char *)ea)>>7;
			*(char *)ea = -(*(char *)ea);
			Rm = (*(char *)ea)>>7;
			cc_n = (*(char *)ea < 0);
			cc_z = (*(char *)ea == 0);
			cc_v = (Dm && Rm);
			cc_c = (Dm || Rm);
			cc_x = cc_c;
			break;
		case 1:
			Dm = (*(short *)ea)>>15;
			*(short *)ea = -(*(short *)ea);
			Rm = (*(short *)ea)>>15;
			cc_n = (*(short *)ea < 0);
			cc_z = (*(short *)ea == 0);
			cc_v = (Dm && Rm);
			cc_c = (Dm || Rm);
			cc_x = cc_c;
			break;
		case 2:
			Dm = (*(int *)ea)>>31;
			*(int *)ea = -(*(int *)ea);
			Rm = (*(int *)ea)>>31;
			cc_n = (*(int *)ea < 0);
			cc_z = (*(int *)ea == 0);
			cc_v = (Dm && Rm);
			cc_c = (Dm || Rm);
			cc_x = cc_c;
			break;
	}
	
	store_ccr_flags();
}



void op_negx(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Dm;
	int Rm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("NEGX");
	#endif
	
	get_ccr_flags();
	calc_effective_address(1 << size, ea_mode, ea_reg);
	
	switch(size){
		case 0:
			Dm = *(char *)ea;
			*(char *)ea = -(*(char *)ea) - cc_x;
			Rm = *(char *)ea;
			break;
		case 1:
			Dm = *(short *)ea;
			*(short *)ea = -(*(short *)ea) - cc_x;
			Rm = *(short *)ea;
			break;
		case 2:
			Dm = *(int *)ea;
			*(int *)ea = -(*(int *)ea) - cc_x;
			Rm = *(int *)ea;
			break;
	}
	
	cc_n = (Rm < 0);
	if(Rm != 0) cc_z = 0;
	cc_v = (Dm && Rm);
	Dm >>= 31;
	Rm >>= 31;
	cc_c = (Dm || Rm);
	cc_x = cc_c;
	store_ccr_flags();
}



void op_not(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Rm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("NOT");
	#endif
	
	get_ccr_flags();
	calc_effective_address(1 << size, ea_mode, ea_reg);
	
	switch(size){
		case 0:
			*(char *)ea = ~(*(char *)ea);
			Rm = *(char *)ea;
			break;
		case 1:
			*(short *)ea = ~(*(short *)ea);
			Rm = *(short *)ea;
			break;
		case 2:
			*(int *)ea = ~(*(int *)ea);
			Rm = *(int *)ea;
			break;
	}
	
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_or(short data){
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Sm;
	int Dm;
	int Rm;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("OR");
	#endif
	
	get_ccr_flags();
	calc_effective_address(1 << (opmode & 3), ea_mode, ea_reg);
	
	if(opmode & 4){
		switch(opmode & 3){
			case 0:
				Sm = reg_d[reg];
				Dm = *(char *)ea;
				i = *(char *)ea;
				i |= reg_d[reg];
				*(char *)ea = (char)i;
				Rm = *(char *)ea;
				cc_n = ((Rm & 0x80) != 0);
				break;
			case 1:
				Sm = reg_d[reg];
				Dm = *(short *)ea;
				i = *(short *)ea;
				i |= reg_d[reg];
				*(short *)ea = (short)i;
				Rm = *(short *)ea;
				cc_n = ((Rm & 0x8000) != 0);
				break;
			case 2:
				Sm = reg_d[reg];
				Dm = *(int *)ea;
				*(int *)ea |= reg_d[reg];
				Rm = *(int *)ea;
				cc_n = ((Rm & 0x80000000) != 0);
				break;
		}
	}
	else{
		switch(opmode & 3){
			case 0:
				Sm = *(char *)ea;
				Dm = reg_d[reg];
				i = reg_d[reg] & 0xFF;
				i |= *(char *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFFFF00) + (unsigned char)i;
				Rm = reg_d[reg];
				cc_n = ((Rm & 0x80000000) != 0);
				break;
			case 1:
				Sm = *(short *)ea;
				Dm = reg_d[reg];
				i = reg_d[reg] & 0xFFFF;
				i |= *(short *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFF0000) + (unsigned short)i;
				Rm = reg_d[reg];
				cc_n = ((Rm & 0x80000000) != 0);
				break;
			case 2:
				Sm = *(int *)ea;
				Dm = reg_d[reg];
				reg_d[reg] |= *(int *)ea;
				Rm = reg_d[reg];
				cc_n = ((Rm & 0x80000000) != 0);
				break;
		}
	}
	
	cc_z = (Rm == 0);
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_ori(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Rm;
	
	unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("ORI");
	#endif
	
	if(data == 0x3C){
		imm = read_script(2, MOTOROLA);
		ea = (int)&sr;
		*(char *)ea |= imm;
		return;
	}
	if(data == 0x7C){
		imm = read_script(2, MOTOROLA);
		ea = (int)&sr;
		*(short *)ea |= imm;
		return;
	}
	
	get_ccr_flags();
	calc_effective_address(1 << size, ea_mode, ea_reg);
	
	switch(size){
		case 0:
			imm = read_script(2, MOTOROLA);
			*(char *)ea |= imm;
			Rm = *(char *)ea;
			break;
		case 1:
			imm = read_script(2, MOTOROLA);
			*(short *)ea |= imm;
			Rm = *(short *)ea;
			break;
		case 2:
			imm = read_script(4, MOTOROLA);
			*(int *)ea |= imm;
			Rm = *(int *)ea;
			break;
	}
	
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	cc_v = 0;
	cc_c = 0;
}



void op_sub(short data){
	char reg = (data >> 9) & 7;
	char opmode = (data >> 6) & 7;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Sm;
	int Dm;
	int Rm;
	
	unsigned int i;
	
	if(opmode == 3 || opmode == 7){
		#ifdef ENABLE_LOGGING
		WriteLog("SUBA");
		#endif
		calc_effective_address((opmode >> 1) + 1, ea_mode, ea_reg);
	}
	else{
		#ifdef ENABLE_LOGGING
		WriteLog("SUB");
		#endif
		calc_effective_address(1 << (opmode & 3), ea_mode, ea_reg);
	}
	
	if(opmode == 3 || opmode == 7){
		// SUBA
		switch(opmode){
			case 3:	// word
				i = reg_a[reg] & 0xFFFF;
				i -= *(short *)ea;
				reg_a[reg] = (reg_a[reg] & 0xFFFF0000) + (unsigned short)i;
				break;
			case 7:	// long
				reg_a[reg] -= *(int *)ea;
				break;
		}
	}
	else if(opmode & 4){
		// SUB
		switch(opmode & 3){
			case 0:
				Sm = (char)reg_d[reg];
				Dm = *(char *)ea;
				i = *(char *)ea;
				i -= reg_d[reg];
				*(char *)ea = (char)i;
				Rm = *(char *)ea;
				break;
			case 1:
				Sm = (short)reg_d[reg];
				Dm = *(short *)ea;
				i = *(short *)ea;
				i -= reg_d[reg];
				*(short *)ea = (short)i;
				Rm = *(short *)ea;
				break;
			case 2:
				Sm = reg_d[reg];
				Dm = *(int *)ea;
				*(int *)ea -= reg_d[reg];
				Rm = *(int *)ea;
				break;
		}
	}
	else{
		// SUB
		switch(opmode & 3){
			case 0:
				Sm = *(char *)ea;
				Dm = (char)reg_d[reg];
				i = reg_d[reg] & 0xFF;
				i -= *(char *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFFFF00) + (unsigned char)i;
				Rm = (char)reg_d[reg];
				break;
			case 1:
				Sm = *(short *)ea;
				Dm = (short)reg_d[reg];
				i = reg_d[reg] & 0xFFFF;
				i -= *(short *)ea;
				reg_d[reg] = (reg_d[reg] & 0xFFFF0000) + (unsigned short)i;
				Rm = (short)reg_d[reg];
				break;
			case 2:
				Sm = *(int *)ea;
				Dm = reg_d[reg];
				reg_d[reg] -= *(int *)ea;
				Rm = reg_d[reg];
				break;
		}
	}
	
	if(!(opmode == 3 || opmode == 7)){
		get_ccr_flags();
		cc_n = (Rm < 0);
		cc_z = (Rm == 0);
		Sm >>= 31;
		Dm >>= 31;
		Rm >>= 31;
		cc_v = ((!Sm && Dm && !Rm) || (Sm && !Dm && Rm));
		cc_c = ((Sm && !Dm) || (Rm && !Dm) || (Sm && Rm));
		cc_x = cc_c;
		store_ccr_flags();
	}
}



void op_subi(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Sm;
	int Dm;
	int Rm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("SUBI");
	#endif
	
	calc_effective_address(1 << size, ea_mode, ea_reg);
	switch(size){
		case 0:
			imm = read_script(2, MOTOROLA);
			Sm = (char)imm;
			Dm = *(char *)ea;
			*(char *)ea -= imm;
			Rm = *(char *)ea;
			break;
		case 1:
			imm = read_script(2, MOTOROLA);
			Sm = (short)imm;
			Dm = *(short *)ea;
			*(short *)ea -= imm;
			Rm = *(short *)ea;
			break;
		case 2:
			imm = read_script(4, MOTOROLA);
			Sm = imm;
			Dm = *(int *)ea;
			*(int *)ea -= imm;
			Rm = *(int *)ea;
			break;
	}
	
	get_ccr_flags();
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	Sm >>= 31;
	Dm >>= 31;
	Rm >>= 31;
	cc_v = ((!Sm && Dm && !Rm) || (Sm && !Dm && Rm));
	cc_c = ((Sm && !Dm) || (Rm && !Dm) || (Sm && Rm));
	cc_x = cc_c;
	store_ccr_flags();
}



void op_subq(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	
	int Sm;
	int Dm;
	int Rm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("SUBQ");
	#endif
	
	calc_effective_address(1 << size, ea_mode, ea_reg);
	switch(size){
		case 0:
			imm = (data >> 9) & 7;
			if(!imm) imm = 8;
			Sm = (char)imm;
			Dm = *(char *)ea;
			*(char *)ea -= imm;
			Rm = *(char *)ea;
			break;
		case 1:
			imm = (data >> 9) & 7;
			if(!imm) imm = 8;
			Sm = (short)imm;
			Dm = *(short *)ea;
			*(short *)ea -= imm;
			Rm = *(short *)ea;
			break;
		case 2:
			imm = (data >> 9) & 7;
			if(!imm) imm = 8;
			Sm = (int)imm;
			Dm = *(int *)ea;
			*(int *)ea -= imm;
			Rm = *(int *)ea;
			break;
	}
	
	get_ccr_flags();
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	Sm >>= 31;
	Dm >>= 31;
	Rm >>= 31;
	cc_v = ((!Sm && Dm && !Rm) || (Sm && !Dm && Rm));
	cc_c = ((Sm && !Dm) || (Rm && !Dm) || (Sm && Rm));
	cc_x = cc_c;
	store_ccr_flags();
}



void op_swap(short data){
	char reg = data & 7;
	
	#ifdef ENABLE_LOGGING
	WriteLog("SWAP");
	#endif
	
	reg_d[reg] = (reg_d[reg] >> 16) + (reg_d[reg] << 16);
	
	get_ccr_flags();
	cc_n = (reg_d[reg] >> 31);
	cc_z = (reg_d[reg] == 0);
	cc_v = 0;
	cc_c = 0;
	store_ccr_flags();
}



void op_tst(short data){
	char size = (data >> 6) & 3;
	char ea_mode = (data >> 3) & 7;
	char ea_reg = data & 7;
	int Rm;
	
	//unsigned int i;
	
	#ifdef ENABLE_LOGGING
	WriteLog("TST");
	#endif
	
	calc_effective_address(1 << size, ea_mode, ea_reg);
	
	switch(size){
		case 0:
			Rm = *(char *)ea;
			break;
		case 1:
			Rm = *(short *)ea;
			break;
		case 2:
			Rm = *(int *)ea;
			break;
	}
	
	get_ccr_flags();
	
	cc_n = (Rm < 0);
	cc_z = (Rm == 0);
	cc_v = 0;
	cc_c = 0;
	
	store_ccr_flags();
	
	//if(pc >= 0x7A && pc <= 0x7E){
	//	allegro_message("*ea = %X\nram_68k = %X\n\nea = %X\n&ram_68k = %X\n\nRm = %X\ncc_z = %X", *(char *)ea, ram_68k[0xFFFF - 0xC3F2], ea, &ram_68k[0xFFFF - 0xC3F2], Rm, cc_z);
	//	rest(35);
	//}
}
