package miggy.cpupoet;

public class CoreALU {
	/*
	 * status register privileged flags
	 */

	/**
	 * Trace flag for all executed instructions
	 */
	public static final int SR_T1 = 1 << 15;
	/**
	 * Trace flag for instruction flow changes
	 */
	public static final int SR_T0 = 1 << 14;
	/**
	 * Supervisor flag
	 */
	public static final int SR_S = 1 << 13;
	/**
	 * Supervisor Master flag
	 */
	public static final int SR_M = 1 << 12;
	/**
	 * Interrupt level mask
	 */
	public static final int SR_I = 7 << 8;

	/*
	 * Special status word bus flags
	 */

	/**
	 * Re-run flag: 0= processor re-run (default), 1 = software re-run. when not
	 * used by RTE, 1 means a read/write is running.
	 */
	public static final int SSW_RR = 1 << 15;
	/**
	 * Instruction fetch to the Instruction Input Buffer.
	 */
	public static final int SSW_IF = 1 << 13;
	/**
	 * Data fetch to the Data Input Buffer.
	 */
	public static final int SSW_DF = 1 << 12;
	/**
	 * Read-Modify-Write cycle.
	 */
	public static final int SSW_RM = 1 << 11;
	/**
	 * High byte transfer from the Data Output Buffer or to the Data Input Buffer.
	 */
	public static final int SSW_HB = 1 << 10;
	/**
	 * Byte transfer flag: HB selects the high or low byte of the transfer register.
	 * If BY is clear, the transfer is word
	 */
	public static final int SSW_BY = 1 << 9;
	/**
	 * Read/Write flag: 0 = write, 1 = read.
	 */
	public static final int SSW_RW = 1 << 8;
	/**
	 * If set, indicates a 32 bits wide transfer
	 */
	public static final int SSW_32 = 1 << 7;
	/**
	 * If set, indicates that 32 bits transfer has been handled by software
	 */
	public static final int SSW_WD = 1 << 6;
	/**
	 * If set, indicates last transfer produced a bus error
	 */
	public static final int SSW_BR = 1 << 5;
	/**
	 * If set, indicates that a reset is pending
	 */
	public static final int SSW_RS = 1 << 4;
	/**
	 * If set, indicates that cpu is halted
	 */
	public static final int SSW_HL = 1 << 3;
	/**
	 * If set, indicates that current access is made in supervisor (interrupt or
	 * master) mode
	 */
	public static final int SSW_S = 1 << 2;
	/**
	 * If set, indicates that CPU is fetching a program word
	 */
	public static final int SSW_P = 1 << 1;
	/**
	 * If set, indicates that CPU is fetching a data word
	 */
	public static final int SSW_D = 1 << 0;

	/*
	 * Special status word internal flags
	 */

	/**
	 * fetch effective address after calculation
	 */
	public static final int SSWI_EAFH = 1 << 11;
	/**
	 * Exit after a RMW cycle
	 */
	public static final int SSWI_XRMW = 1 << 6;
	/**
	 * Downgrade to 68000 for Bcc/dais
	 */
	public static final int SSWI_DNGR = 1 << 5;
	/**
	 * Execute only a single instruction
	 */
	public static final int SSWI_SNGL = 1 << 4;
	/**
	 * Enable trap format format 0x2 when applicable
	 */
	public static final int SSWI_FMT2 = 1 << 3;
	/**
	 * Global interrupt auto-vectored flag
	 */
	public static final int SSWI_AVEC = 1 << 2;
	/**
	 * Signal a double bus fault occurred (unrecoverable HALT state)
	 */
	public static final int SSWI_DERR = 1 << 1;
	/**
	 * Persist slice (save over-runned cycles on each call to execute) and apply
	 * over-runned remaining cycles on each call to execute.
	 */
	public static final int SSWI_PSLC = 1 << 0;

	/*
	 * Effective address extension word
	 */

	/**
	 * extension word register index
	 */
	public static final int EAX_REG = 15 << 12;
	/**
	 * extension word index size
	 */
	public static final int EAX_SIZ = 1 << 11;
	/**
	 * extension word scale
	 */
	public static final int EAX_SCL = 3 << 9;
	/**
	 * extension word type
	 */
	public static final int EAX_EXT = 1 << 8;
	/**
	 * extension word base register suppress
	 */
	public static final int EAX_BS = 1 << 7;
	/**
	 * extension word index suppress
	 */
	public static final int EAX_IS = 1 << 6;
	/**
	 * extension word base displacement size
	 */
	public static final int EAX_BSS = 3 << 4;
	/**
	 * extension word index/indirect selection
	 */
	public static final int EAX_ISL = 7 << 0;

	/*
	 * Condition code register flags
	 */

	/**
	 * Carry
	 */
	public static final int FL_C = 0x01;
	/**
	 * Overflow
	 */
	public static final int FL_V = 0x02;
	/**
	 * Zero
	 */
	public static final int FL_Z = 0x04;
	/**
	 * Negative
	 */
	public static final int FL_N = 0x08;
	/**
	 * Extend
	 */
	public static final int FL_X = 0x10;

	/*
	 * Available conditions for 68k
	 */

	/**
	 * True
	 */
	public static final int CC_T = 0x0;
	/**
	 * False
	 */
	public static final int CC_F = 0x1;
	/**
	 * High
	 */
	public static final int CC_HI = 0x2;
	/**
	 * Low or same
	 */
	public static final int CC_LS = 0x3;
	/**
	 * Carry clear
	 */
	public static final int CC_CC = 0x4;
	/**
	 * Carry set
	 */
	public static final int CC_CS = 0x5;
	/**
	 * Not equal
	 */
	public static final int CC_NE = 0x6;
	/**
	 * Equal
	 */
	public static final int CC_EQ = 0x7;
	/**
	 * Overflow clear
	 */
	public static final int CC_VC = 0x8;
	/**
	 * Overflow set
	 */
	public static final int CC_VS = 0x9;
	/**
	 * Plus
	 */
	public static final int CC_PL = 0xa;
	/**
	 * Minus
	 */
	public static final int CC_MI = 0xb;
	/**
	 * Greater or equal
	 */
	public static final int CC_GE = 0xc;
	/**
	 * Less than
	 */
	public static final int CC_LT = 0xd;
	/**
	 * Greater than
	 */
	public static final int CC_GT = 0xe;
	/**
	 * Less or equal
	 */
	public static final int CC_LE = 0xf;

	/**
	 * data and address registers. container register in that order : data, address,
	 * usp, isp, msp
	 */
	protected final int[] dar = new int[18];

	/**
	 * Status Register.
	 */
	protected int sr = 0;
	/**
	 * Special status word. Contains information about ongoing bus, halt and reset
	 * states.
	 */
	protected int ssw = 0;
	/**
	 * Special status word (internal). purpose of this register is to record pending
	 * traces and interrupts as well as global runtime flags. when saving CPU
	 * context, only pending stuff is saved in stack trace.
	 */
	protected int sswi = 0;
	/**
	 * Vector base register
	 */
	protected int vbr;
	/**
	 * Source function code
	 */
	protected int sfc;
	/**
	 * Destination function code
	 */
	protected int dfc;

	/**
	 * retrieve dar index for the current stack pointer (usp, isp or msp) according
	 * to status register value.
	 * 
	 * @param sr value of SR
	 * @return index of stack pointer
	 */
	protected static final int spi(int sr) {
		int sp = 15;
		if ((sr & SR_S) != 0) {
			sp = (sr & SR_M) != 0 ? 17 : 16;
		}
		return sp;
	}

	public final void setDARB(int index, int value) {
		index &= 0xf;

		if (index == 0xf) {
			index = spi(sr);
		}

		dar[index] = (dar[index] & ~0xff) | (value & 0xff);
	}

	public final byte getDARB(int index) {
		index &= 0xf;

		if (index == 0xf) {
			index = spi(sr);
		}

		return (byte) dar[index];
	}

	public final void setDARW(int index, int value) {
		index &= 0xf;

		if (index == 0xf) {
			index = spi(sr);
		}

		dar[index] = (dar[index] & ~0xffff) | (value & 0xffff);
	}

	public final short getDARW(int index) {
		index &= 0xf;

		if (index == 0xf) {
			index = spi(sr);
		}

		return (short) dar[index];
	}

	public final void setDARL(int index, int value) {
		index &= 0xf;

		if (index == 0xf) {
			index = spi(sr);
		}

		dar[index] = value;
	}

	public final int getDARL(int index) {
		index &= 0xf;

		if (index == 0xf) {
			index = spi(sr);
		}

		return dar[index];
	}

	public final void setUSP(int value) {
		dar[15] = value;
	}

	public final int getUSP() {
		return dar[15];
	}

	public final void setISP(int value) {
		dar[16] = value;
	}

	public final int getISP() {
		return dar[16];
	}

	public final void setMSP(int value) {
		dar[17] = value;
	}

	public final int getMSP() {
		return dar[17];
	}

	public final void setSFC(int value) {
		sfc = value & 0x7;
	}

	public final int getSFC() {
		return sfc;
	}

	public final void setDFC(int value) {
		dfc = value & 0x7;
	}

	public final int getDFC() {
		return dfc;
	}

	public final void setVBR(int value) {
		vbr = value;
	}

	public final int getVBR() {
		return vbr;
	}

	/**
	 * @return contents of SR register
	 */
	public final int getSR() {
		return sr;
	}

	/**
	 * set contents of SR register
	 * 
	 * @param value value to be set. Only ALU flags are supported. Other bits are
	 *              set as '0'
	 */
	public final void setSR(int value) {
		int esr = (sr ^ value) & (SR_T1 | SR_T0 | SR_S | SR_M | SR_I | FL_C | FL_V | FL_Z | FL_N | FL_X);

		sr ^= esr;
	}

	/**
	 * set or clear bits in SR. undefined bits can't be set or cleared.
	 * 
	 * @param set SR bits to be set
	 * @param clr SR bits to be cleared
	 * @return new SR value
	 */
	public final int setclrSR(int set, int clr) {
		int esr = sr & clr & (SR_T1 | SR_T0 | SR_S | SR_M | SR_I | FL_C | FL_V | FL_Z | FL_N | FL_X);

		return sr ^= esr ^ (set & (SR_T1 | SR_T0 | SR_S | SR_M | SR_I | FL_C | FL_V | FL_Z | FL_N | FL_X));
	}

	/**
	 * @return contents of SSW register
	 */
	public final int getSSW() {
		return ssw;
	}

	/**
	 * @return contents of SSWI register
	 */
	public final int getSSWI() {
		return ssw;
	}

	/**
	 * set or clear bits in SSW. undefined or internally handled bits can't be set
	 * or cleared.
	 * 
	 * @param set SSW bits to be set
	 * @param clr SSW bits to be cleared
	 * @return new SSW value
	 */
	public final int setclrSSW(int set, int clr) {
		/* RS/HL are always modifiable */
		int mask = SSW_RS | SSW_HL;

		if ((sswi & SSWI_DERR) != 0) {
			/* when in double bus fault, HALT can't be cleared */
			clr &= ~SSW_HL;
		}

		if ((ssw & SSW_RR) != 0) {
			/* bus error may be modified if a bus transfer is running */
			mask |= SSW_BR;

			if ((ssw & SSW_32) != 0) {
				/* wide access is allowed for 32 bits transfer */
				mask |= SSW_WD;
			}
		}

//		int essw = ssw & clr & mask;
//
//		return ssw ^= essw ^ (set & mask);
		return ssw = (ssw & (~(clr & mask))) | (set & mask);
	}

	/**
	 * set or clear bits in SSWI. undefined or internally handled bits can't be set
	 * or cleared.
	 * 
	 * @param set SSWI bits to be set
	 * @param clr SSWI bits to be cleared
	 * @return new SSWI value
	 */
	public final int setclrSSWI(int set, int clr) {
		int mask = SSWI_XRMW | SSWI_DNGR | SSWI_SNGL | SSWI_FMT2 | SSWI_AVEC | SSWI_PSLC;
		//int esswi = sswi & clr & (SSWI_SNGL | SSWI_FMT2 | SSWI_AVEC | SSWI_PSLC);
		//
		//return sswi ^= esswi ^ (set & (SSWI_SNGL | SSWI_AVEC | SSWI_PSLC));
		return sswi = (sswi & (~(clr & mask))) | (set & mask);
	}

	/**
	 * @return contents of CCR register
	 */
	public final int getCCR() {
		return sr & (FL_C | FL_V | FL_Z | FL_N | FL_X);
	}

	/**
	 * set contents of CCR register
	 * 
	 * @param value value to be set. Only ALU flags are supported. Other bits are
	 *              set as '0'
	 */
	public final void setCCR(int value) {
		int eccr = (sr ^ value) & (FL_C | FL_V | FL_Z | FL_N | FL_X);

		sr ^= eccr;
	}

	/**
	 * set or clear bits in CCR. undefined bits can't be set or cleared.
	 * 
	 * @param set CCR bits to be set
	 * @param clr CCR bits to be cleared
	 * @return new SR value
	 */
	public final int setclrCCR(int set, int clr) {
		int eccr = sr & clr & (FL_C | FL_V | FL_Z | FL_N | FL_X);

		return sr ^= eccr ^ (set & (FL_C | FL_V | FL_Z | FL_N | FL_X));
	}

	/**
	 * check if the given condition is met using actual ALU flags.
	 * 
	 * @param condition condition to be tested
	 * @return 'true' if condition met, 'false' otherwise.
	 */
	public final boolean testCC(int condition) {
		return testCC(sr, condition);
	}

	protected static final boolean testCC(int CCR, int condition) {
		boolean result = false;

		switch (condition) {
		case CC_T:
			/* The T condition is always true */
			result = true;
			break;
		case CC_F:
			/* false condition is always... false */
			result = false;
		default:
			break;
		case CC_HI:
			result = ((CCR & (FL_C | FL_Z)) == 0);
			break;
		case CC_LS:
			result = ((CCR & (FL_C | FL_Z)) != 0);
			break;
		case CC_CC:
			/* carry clear... check that the carry flag is not set */
			result = ((CCR & FL_C) == 0);
			break;
		case CC_CS:
			/* carry set, check if the carry flag is set */
			result = ((CCR & FL_C) != 0);
			break;
		case CC_NE:
			result = ((CCR & FL_Z) == 0);
			break;
		case CC_EQ:
			/* Zero, check if the zero flag is set */
			result = ((CCR & FL_Z) != 0);
			break;
		case CC_VC:
			result = ((CCR & FL_V) == 0);
			break;
		case CC_VS:
			result = ((CCR & FL_V) != 0);
			break;
		case CC_PL:
			result = ((CCR & FL_N) == 0);
			break;
		case CC_MI:
			result = ((CCR & FL_N) != 0);
			break;
		case CC_GE:
			CCR &= FL_N | FL_V;

			result = (CCR == 0) || (CCR == (FL_N | FL_V));
			break;
		case CC_LT:
			CCR &= FL_N | FL_V;

			result = (CCR == FL_N) || (CCR == FL_V);
			break;
		case CC_GT:
			CCR &= FL_N | FL_V | FL_Z;

			result = (CCR == 0) || (CCR == (FL_N | FL_V));
			break;
		case CC_LE:
			CCR &= FL_N | FL_V | FL_Z;

			result = ((CCR & FL_Z) != 0) || (CCR == FL_N) || (CCR == FL_V);
			break;
		}

		return result;
	}

	public final byte byte_abcd(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte br = (byte) (dst + src + ((sr & FL_X) >> 4));
		int sbr = br >>> 1; /* trick for full 32 bits bcd addition */
		int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
		int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
		int corf = (bc | dc) - ((bc | dc) >>> 2);
		byte dr = (byte) (br + corf);

		int v = ((~br & dr) >> 30) & FL_V;
		int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
		int n = (dr >> 28) & FL_N;
		int z = ((dr | -dr) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return dr;
	}

	public final short word_abcd(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short br = (short) (dst + src + ((sr & FL_X) >> 4));
		int sbr = br >>> 1; /* trick for full 32 bits bcd addition */
		int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
		int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
		int corf = (bc | dc) - ((bc | dc) >>> 2);
		short dr = (short) (br + corf);

		int v = ((~br & dr) >> 30) & FL_V;
		int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
		int n = (dr >> 28) & FL_N;
		int z = ((dr | -dr) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return dr;
	}

	public final int long_abcd(int src, int dst) {
		int br = dst + src + ((sr & FL_X) >> 4);
		int sbr = br >>> 1; /* trick for full 32 bits bcd addition */
		int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
		int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
		int corf = (bc | dc) - ((bc | dc) >>> 2);
		int dr = br + corf;

		int v = ((~br & dr) >> 30) & FL_V;
		int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
		int n = (dr >> 28) & FL_N;
		int z = ((dr | -dr) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return dr;
	}

	public final byte byte_add(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte res = (byte) (dst + src);

		int v = (((src ^ res) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | dst) & ~res) | (src & dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);

		return res;
	}

	public final short word_add(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short res = (short) (dst + src);

		int v = (((src ^ res) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | dst) & ~res) | (src & dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);

		return res;
	}

	public final int long_add(int src, int dst) {
		int res = dst + src;

		int v = (((src ^ res) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | dst) & ~res) | (src & dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);

		return res;
	}

	public final byte byte_addx(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte res = (byte) (dst + src + ((sr & FL_X) >> 4));

		int v = (((src ^ res) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | dst) & ~res) | (src & dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = ((res | -res) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return res;
	}

	public final short word_addx(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short res = (short) (dst + src + ((sr & FL_X) >> 4));

		int v = (((src ^ res) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | dst) & ~res) | (src & dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = ((res | -res) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return res;
	}

	public final int long_addx(int src, int dst) {
		int res = dst + src + ((sr & FL_X) >> 4);

		int v = (((src ^ res) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | dst) & ~res) | (src & dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = ((res | -res) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return res;
	}

	public final byte byte_and(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte res = (byte) (dst & src);

		res_tst(res);

		return res;
	}

	public final short word_and(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short res = (short) (dst & src);

		res_tst(res);

		return res;
	}

	public final int long_and(int src, int dst) {
		int res = dst & src;

		res_tst(res);

		return res;
	}

	public final byte byte_asl(int shift, int dst) {
		shift &= 0x3f;

		byte res = (byte) dst;

		if (shift > 0) {
			int mask = -1 << (8 - Math.min(shift, 8));
			int vout = res & mask;
			int cx = 0;
			int v = (vout == 0) || (vout == mask) ? 0 : FL_V;

			if (shift <= 8) {
				res <<= shift - 1;
				cx = (res >> 31) & (FL_C | FL_X);
				res <<= 1;
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final short word_asl(int shift, int dst) {
		shift &= 0x3f;

		short res = (short) dst;

		if (shift > 0) {
			int mask = -1 << (16 - Math.min(shift, 16));
			int vout = res & mask;
			int cx = 0;
			int v = (vout == 0) || (vout == mask) ? 0 : FL_V;

			if (shift <= 16) {
				res <<= shift - 1;
				cx = (res >> 31) & (FL_C | FL_X);
				res <<= 1;
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final int long_asl(int shift, int dst) {
		shift &= 0x3f;

		int res = dst;

		if (shift > 0) {
			int mask = -1 << (32 - Math.min(shift, 32));
			int vout = res & mask;
			int cx = 0;
			int v = (vout == 0) || (vout == mask) ? 0 : FL_V;

			if (shift <= 32) {
				res <<= shift - 1;
				cx = (res >> 31) & (FL_C | FL_X);
				res <<= 1;
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final byte byte_asr(int shift, int dst) {
		shift &= 0x3f;

		byte res = (byte) dst;

		if (shift > 0) {
			int cx = 0;

			res >>= Math.min(shift, 8) - 1;
			cx = res & FL_C; /* set carry */
			cx |= cx << 4; /* also set eXtend */
			res >>= 1; /* perform final shift */

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final short word_asr(int shift, int dst) {
		shift &= 0x3f;

		short res = (short) dst;

		if (shift > 0) {
			int cx = 0;

			res >>= Math.min(shift, 16) - 1;
			cx = res & FL_C; /* set carry */
			cx |= cx << 4; /* also set eXtend */
			res >>= 1; /* perform final shift */

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final int long_asr(int shift, int dst) {
		shift &= 0x3f;

		int res = dst;

		if (shift > 0) {
			int cx = 0;

			res >>= Math.min(shift, 32) - 1;
			cx = res & FL_C; /* set carry */
			cx |= cx << 4; /* also set eXtend */
			res >>= 1; /* perform final shift */

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final byte byte_bchg(int bit, int dst) {
		bit &= 0x7;

		int src = 1 << bit;
		int res = dst & src & 0xff;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return (byte) (dst ^ src);
	}

	public final short word_bchg(int bit, int dst) {
		bit &= 0xf;

		int src = 1 << bit;
		int res = dst & src & 0xffff;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return (short) (dst ^ src);
	}

	public final int long_bchg(int bit, int dst) {
		bit &= 0x1f;

		int src = 1 << bit;
		int res = dst & src;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return dst ^ src;
	}

	public final byte byte_bclr(int bit, int dst) {
		bit &= 0x7;

		int src = 1 << bit;
		int res = dst & src & 0xff;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return (byte) (dst & (~src));
	}

	public final short word_bclr(int bit, int dst) {
		bit &= 0xf;

		int src = 1 << bit;
		int res = dst & src & 0xffff;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return (short) (dst & (~src));
	}

	public final int long_bclr(int bit, int dst) {
		bit &= 0x1f;

		int src = 1 << bit;
		int res = dst & src;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return (dst & (~src));
	}

	public final byte byte_bset(int bit, int dst) {
		bit &= 0x7;

		int src = 1 << bit;
		int res = dst & src & 0xff;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return (byte) (dst | src);
	}

	public final short word_bset(int bit, int dst) {
		bit &= 0xf;

		int src = 1 << bit;
		int res = dst & src & 0xffff;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return (short) (dst | src);
	}

	public final int long_bset(int bit, int dst) {
		bit &= 0x1f;

		int src = 1 << bit;
		int res = dst & src;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;

		return dst | src;
	}

	public final void byte_btst(int bit, int dst) {
		bit &= 0x7;

		int res = dst & (1 << bit) & 0xff;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;
	}

	public final void word_btst(int bit, int dst) {
		bit &= 0xf;

		int res = dst & (1 << bit) & 0xffff;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;
	}

	public final void long_btst(int bit, int dst) {
		bit &= 0x1f;

		int res = dst & (1 << bit);
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ z) & FL_Z;
	}

	public final boolean word_chk(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		int z = (~((dst | -dst) >> 31)) & FL_Z;

		if (dst < 0) {
			/* set N flag and take chk trap */
			sr ^= (sr ^ (z | FL_N)) & (FL_C | FL_V | FL_Z | FL_N);

			return true;
		} else if (dst > src) {
			/* clear N flag and take chk trap */
			sr ^= (sr ^ z) & (FL_C | FL_V | FL_Z | FL_N);

			return true;
		}

		/* leave N flag and continue execution */
		sr ^= (sr ^ z) & (FL_C | FL_V | FL_Z);

		return false;
	}

	public final boolean long_chk(int src, int dst) {
		int z = (~((dst | -dst) >> 31)) & FL_Z;

		if (dst < 0) {
			/* set N flag and take chk trap */
			sr ^= (sr ^ (z | FL_N)) & (FL_C | FL_V | FL_Z | FL_N);

			return true;
		} else if (dst > src) {
			/* clear N flag and take chk trap */
			sr ^= (sr ^ z) & (FL_C | FL_V | FL_Z | FL_N);

			return true;
		}

		/* leave N flag and continue execution */
		sr ^= (sr ^ z) & (FL_C | FL_V | FL_Z);

		return false;
	}

	public final void byte_cmp(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte res = (byte) (dst - src);

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int c = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (c | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N);
	}

	public final void word_cmp(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short res = (short) (dst - src);

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int c = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (c | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N);
	}

	public final void long_cmp(int src, int dst) {
		int res = dst - src;

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int c = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (c | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N);
	}

	public final byte byte_eor(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte res = (byte) (dst ^ src);

		res_tst(res);

		return res;
	}

	public final short word_eor(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short res = (short) (dst ^ src);

		res_tst(res);

		return res;
	}

	public final int long_eor(int src, int dst) {
		int res = dst ^ src;

		res_tst(res);

		return res;
	}

	public final byte byte_lsl(int shift, int dst) {
		shift &= 0x3f;

		byte res = (byte) dst;

		if (shift > 0) {
			int cx = 0;

			if (shift <= 8) {
				res <<= shift - 1;
				cx = (res >> 31) & (FL_C | FL_X);
				res <<= 1; /* perform final shift */
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final short word_lsl(int shift, int dst) {
		shift &= 0x3f;

		short res = (short) dst;

		if (shift > 0) {
			int cx = 0;

			if (shift <= 16) {
				res <<= shift - 1;
				cx = (res >> 31) & (FL_C | FL_X);
				res <<= 1; /* perform final shift */
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final int long_lsl(int shift, int dst) {
		shift &= 0x3f;

		int res = dst;

		if (shift > 0) {
			int cx = 0;

			if (shift <= 32) {
				res <<= shift - 1;
				cx = (res >> 31) & (FL_C | FL_X);
				res <<= 1; /* perform final shift */
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final byte byte_lsr(int shift, int dst) {
		shift &= 0x3f;

		int res = dst & 0xff;

		if (shift > 0) {
			int cx = 0;

			if (shift <= 8) {
				res >>>= shift - 1;
				cx = res & FL_C; /* set carry */
				cx |= cx << 4; /* also set eXtend */
				res = (byte) (res >>> 1); /* perform final shift */
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return (byte) res;
	}

	public final short word_lsr(int shift, int dst) {
		shift &= 0x3f;

		int res = dst & 0xffff;

		if (shift > 0) {
			int cx = 0;

			if (shift <= 16) {
				res >>>= shift - 1;
				cx = res & FL_C; /* set carry */
				cx |= cx << 4; /* also set eXtend */
				res = (short) (res >>> 1); /* perform final shift */
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return (short) res;
	}

	public final int long_lsr(int shift, int dst) {
		shift &= 0x3f;

		int res = dst;

		if (shift > 0) {
			int cx = 0;

			if (shift <= 32) {
				res >>>= shift - 1;
				cx = res & FL_C; /* set carry */
				cx |= cx << 4; /* also set eXtend */
				res >>>= 1; /* perform final shift */
			} else {
				res = 0;
			}

			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cx | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);
		} else {
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
		}

		return res;
	}

	public final byte byte_nbcd(int dst) {
		return byte_sbcd(dst, 0);
	}

	public final short word_nbcd(int dst) {
		return word_sbcd(dst, 0);
	}

	public final int long_nbcd(int dst) {
		return long_sbcd(dst, 0);
	}

	public final byte byte_neg(int dst) {
		return byte_sub(dst, 0);
	}

	public final short word_neg(int dst) {
		return word_sub(dst, 0);
	}

	public final int long_neg(int dst) {
		return long_sub(dst, 0);
	}

	public final byte byte_negx(int dst) {
		return byte_subx(dst, 0);
	}

	public final short word_negx(int dst) {
		return word_subx(dst, 0);
	}

	public final int long_negx(int dst) {
		return long_subx(dst, 0);
	}

	public final byte byte_not(int dst) {
		byte res = (byte) (~dst);

		res_tst(res);

		return res;
	}

	public final short word_not(int dst) {
		short res = (short) (~dst);

		res_tst(res);

		return res;
	}

	public final int long_not(int dst) {
		int res = (~dst);

		res_tst(res);

		return res;
	}

	public final byte byte_or(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte res = (byte) (dst | src);

		res_tst(res);

		return res;
	}

	public final short word_or(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short res = (short) (dst | src);

		res_tst(res);

		return res;
	}

	public final int long_or(int src, int dst) {
		int res = dst | src;

		res_tst(res);

		return res;
	}

	public final byte byte_rol(int shift, int dst) {
		shift &= 0x3f;

		if (shift > 0) {
			shift &= 7;

			byte res = (byte) ((dst << shift) | ((dst & 0xff) >>> (8 - shift)));
			int c = res & FL_C;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (c | z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		} else {
			byte res = (byte) dst;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		}
	}

	public final short word_rol(int shift, int dst) {
		shift &= 0x3f;

		if (shift > 0) {
			shift &= 15;

			short res = (short) ((dst << shift) | ((dst & 0xffff) >>> (16 - shift)));
			int c = res & FL_C;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (c | z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		} else {
			short res = (short) dst;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		}
	}

	public final int long_rol(int shift, int dst) {
		shift &= 0x3f;

		if (shift > 0) {
			shift &= 31;

			int res = (dst << shift) | (dst >>> (32 - shift));
			int c = res & FL_C;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (c | z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		} else {
			int res = dst;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		}
	}

	public final byte byte_ror(int shift, int dst) {
		shift &= 0x3f;

		if (shift > 0) {
			shift &= 7;

			byte res = (byte) ((dst << (8 - shift)) | ((dst & 0xff) >>> shift));
			int cn = (res >> 31) & (FL_N | FL_C);
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cn | z)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		} else {
			byte res = (byte) dst;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		}
	}

	public final short word_ror(int shift, int dst) {
		shift &= 0x3f;

		if (shift > 0) {
			shift &= 7;

			short res = (short) ((dst << (16 - shift)) | ((dst & 0xffff) >>> shift));
			int cn = (res >> 31) & (FL_N | FL_C);
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cn | z)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		} else {
			short res = (short) dst;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		}
	}

	public final int long_ror(int shift, int dst) {
		shift &= 0x3f;

		if (shift > 0) {
			shift &= 7;

			int res = (dst << (32 - shift)) | (dst >>> shift);
			int cn = (res >> 31) & (FL_N | FL_C);
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (cn | z)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		} else {
			int res = dst;
			int n = (res >> 28) & FL_N;
			int z = (~((res | -res) >> 31)) & FL_Z;

			sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);

			return res;
		}
	}

	public final byte byte_sbcd(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		/* compute regular binary substraction */
		byte br = (byte) (dst - src - ((sr & FL_X) >> 4));

		/* normal carry computation */
		int bc = ((~dst & src) | (br & ~dst) | (br & src)) & 0x88888888;
		int corf = bc - (bc >>> 2);
		byte dr = (byte) (br - corf);

		int v = ((br & ~dr) >> 30) & FL_V;
		int cx = ((bc | (~br & dr)) >> 31) & (FL_C | FL_X);
		int n = (dr >> 28) & FL_N;
		int z = ((dr | -dr) >> 31) & FL_Z;

		int eccr = (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		sr ^= eccr;

		return dr;
	}

	public final short word_sbcd(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		/* compute regular binary substraction */
		short br = (short) (dst - src - ((sr & FL_X) >> 4));

		/* normal carry computation */
		int bc = ((~dst & src) | (br & ~dst) | (br & src)) & 0x88888888;
		int corf = bc - (bc >>> 2);
		short dr = (short) (br - corf);

		int v = ((br & ~dr) >> 30) & FL_V;
		int cx = ((bc | (~br & dr)) >> 31) & (FL_C | FL_X);
		int n = (dr >> 28) & FL_N;
		int z = ((dr | -dr) >> 31) & FL_Z;

		int eccr = (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		sr ^= eccr;

		return dr;
	}

	public final int long_sbcd(int src, int dst) {
		/* compute regular binary substraction */
		int br = dst - src - ((sr & FL_X) >> 4);

		/* normal carry computation */
		int bc = ((~dst & src) | (br & ~dst) | (br & src)) & 0x88888888;
		int corf = bc - (bc >>> 2);
		int dr = br - corf;

		int v = ((br & ~dr) >> 30) & FL_V;
		int cx = ((bc | (~br & dr)) >> 31) & (FL_C | FL_X);
		int n = (dr >> 28) & FL_N;
		int z = ((dr | -dr) >> 31) & FL_Z;

		int eccr = (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		sr ^= eccr;

		return dr;
	}

	public final byte byte_sub(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte res = (byte) (dst - src);

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);

		return res;
	}

	public final short word_sub(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short res = (short) (dst - src);

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);

		return res;
	}

	public final int long_sub(int src, int dst) {
		int res = dst - src;

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (cx | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N | FL_X);

		return res;
	}

	public final byte byte_subx(int src, int dst) {
		src = (byte) src;
		dst = (byte) dst;

		byte res = (byte) (dst - src - ((sr & FL_X) >> 4));

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = ((res | -res) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return res;
	}

	public final short word_subx(int src, int dst) {
		src = (short) src;
		dst = (short) dst;

		short res = (short) (dst - src - ((sr & FL_X) >> 4));

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = ((res | -res) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return res;
	}

	public final int long_subx(int src, int dst) {
		int res = dst - src - ((sr & FL_X) >> 4);

		int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
		int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
		int n = (res >> 28) & FL_N;
		int z = ((res | -res) >> 31) & FL_Z;

		sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);

		return res;
	}

	public final void byte_tst(int dst) {
		byte res = (byte) dst;

		res_tst(res);
	}

	public final void word_tst(int dst) {
		short res = (short) dst;

		res_tst(res);
	}

	public final void long_tst(int dst) {
		res_tst(dst);
	}

	private final void res_tst(int res) {
		int n = (res >> 28) & FL_N;
		int z = (~((res | -res) >> 31)) & FL_Z;

		sr ^= (sr ^ (z | n)) & (FL_C | FL_V | FL_Z | FL_N);
	}
}
