public static byte doArithmeticByte(CpuContext ctx, byte a1, byte a2, bool withCarry, bool isSub)
        {
            ushort res; /* To detect carry */

            if (isSub)
            {
                ctx.SETFLAG(Z80Flags.F_N);
                ctx.VALFLAG(Z80Flags.F_H, (((a1 & 0x0F) - (a2 & 0x0F)) & 0x10) != 0);
                res = (ushort)(a1 - a2);
                if (withCarry && ctx.GETFLAG(Z80Flags.F_C)) res--;
            }
            else
            {
                ctx.RESFLAG(Z80Flags.F_N);
                ctx.VALFLAG(Z80Flags.F_H, (((a1 & 0x0F) + (a2 & 0x0F)) & 0x10) != 0);
                res = (ushort)(a1 + a2);
                if (withCarry && ctx.GETFLAG(Z80Flags.F_C)) res++;
            }
            ctx.VALFLAG(Z80Flags.F_S, ((res & 0x80) != 0));
            ctx.VALFLAG(Z80Flags.F_C, ((res & 0x100) != 0));
            ctx.VALFLAG(Z80Flags.F_Z, ((res & 0xff) == 0));
            int minuend_sign = a1 & 0x80;
            int subtrahend_sign = a2 & 0x80;
            int result_sign = res & 0x80;
            bool overflow;
            if (isSub)
            {
                overflow = minuend_sign != subtrahend_sign && result_sign != minuend_sign;
            }
            else
            {
                overflow = minuend_sign == subtrahend_sign && result_sign != minuend_sign;
            }
            ctx.VALFLAG(Z80Flags.F_PV, overflow);
            adjustFlags(ctx, (byte)res);

            return (byte)(res & 0xFF);
        }
 public static ushort doArithmeticWord(CpuContext ctx, ushort a1, ushort a2, bool withCarry, bool isSub)
 {
     if (withCarry && ctx.GETFLAG(Z80Flags.F_C))
         a2++;
     int sum = a1;
     if (isSub)
     {
         sum -= a2;
         ctx.VALFLAG(Z80Flags.F_H, (((a1 & 0x0fff) - (a2 & 0x0fff)) & 0x1000) != 0);
     }
     else
     {
         sum += a2;
         ctx.VALFLAG(Z80Flags.F_H, (((a1 & 0x0fff) + (a2 & 0x0fff)) & 0x1000) != 0);
     }
     ctx.VALFLAG(Z80Flags.F_C, (sum & 0x10000) != 0);
     if (withCarry || isSub)
     {
         int minuend_sign = a1 & 0x8000;
         int subtrahend_sign = a2 & 0x8000;
         int result_sign = sum & 0x8000;
         bool overflow;
         if (isSub)
         {
             overflow = minuend_sign != subtrahend_sign && result_sign != minuend_sign;
         }
         else
         {
             overflow = minuend_sign == subtrahend_sign && result_sign != minuend_sign;
         }
         ctx.VALFLAG(Z80Flags.F_PV, overflow);
         ctx.VALFLAG(Z80Flags.F_S, (sum & 0x8000) != 0);
         ctx.VALFLAG(Z80Flags.F_Z, sum == 0);
     }
     ctx.VALFLAG(Z80Flags.F_N, isSub);
     adjustFlags(ctx, (byte)(sum >> 8));
     return (ushort)sum;
 }
        /* Adjust flags after AND, OR, XOR */
        static void adjustLogicFlag(CpuContext ctx, bool flagH)
        {
            ctx.VALFLAG(Z80Flags.F_S, (ctx.A & 0x80) != 0);
            ctx.VALFLAG(Z80Flags.F_Z, (ctx.A == 0));
            ctx.VALFLAG(Z80Flags.F_H, flagH);
            ctx.VALFLAG(Z80Flags.F_N, false);
            ctx.VALFLAG(Z80Flags.F_C, false);
            ctx.VALFLAG(Z80Flags.F_PV, parityBit[ctx.A]);

            adjustFlags(ctx, ctx.A);
        }
 static void adjustFlagSZP(CpuContext ctx, byte val)
 {
     ctx.VALFLAG(Z80Flags.F_S, (val & 0x80) != 0);
     ctx.VALFLAG(Z80Flags.F_Z, (val == 0));
     ctx.VALFLAG(Z80Flags.F_PV, parityBit[val]);
 }
 public static void adjustFlags(CpuContext ctx, byte val)
 {
     ctx.VALFLAG(Z80Flags.F_5, (val & (byte)Z80Flags.F_5) != 0);
     ctx.VALFLAG(Z80Flags.F_3, (val & (byte)Z80Flags.F_3) != 0);
 }
        public static byte doRRC(CpuContext ctx, bool adjFlags, byte val)
        {
            ctx.VALFLAG(Z80Flags.F_C, (val & 0x01) != 0);
            val >>= 1;
            val |= (byte)((ctx.GETFLAG(Z80Flags.F_C) ? 1 :0) << 7);

            adjustFlags(ctx, val);
            ctx.RESFLAG(Z80Flags.F_H | Z80Flags.F_N);

            if (adjFlags)
                adjustFlagSZP(ctx, val);

            return val;
        }
 public static void doOUTI(CpuContext ctx)
 {
     var value = ctx.ReadMemory1(ctx.HL);
     ctx.B = doIncDec(ctx, ctx.B, true);
     ctx.ioWrite(ctx.BC, value);
     ctx.HL++;
     int flag_value = value + ctx.L;
     ctx.VALFLAG(Z80Flags.F_N, (value & 0x80) != 0);
     ctx.VALFLAG(Z80Flags.F_H, flag_value > 0xff);
     ctx.VALFLAG(Z80Flags.F_C, flag_value > 0xff);
     ctx.VALFLAG(Z80Flags.F_PV, parityBit[(flag_value & 7) ^ ctx.B]);
     adjustFlags(ctx, ctx.B);
 }
        public static byte doRL(CpuContext ctx, bool adjFlags, byte val)
        {
            int CY = ctx.GETFLAG(Z80Flags.F_C) ? 1 :0;
            ctx.VALFLAG(Z80Flags.F_C, (val & 0x80) != 0);
            val <<= 1;
            val |= (byte)CY;

            adjustFlags(ctx, val);
            ctx.RESFLAG(Z80Flags.F_H | Z80Flags.F_N);

            if (adjFlags)
                adjustFlagSZP(ctx, val);

            return val;
        }
 public static void doLDI(CpuContext ctx)
 {
     //ctx->tstates += 2;
     byte val = ctx.ReadMemory1(ctx.HL);
     ctx.WriteMemory1(ctx.DE, val);
     ctx.DE++;
     ctx.HL++;
     ctx.BC--;
     ctx.VALFLAG(Z80Flags.F_5, ((ctx.A + val) & 0x02) != 0);
     ctx.VALFLAG(Z80Flags.F_3, ((Z80Flags)(ctx.A + val) & Z80Flags.F_3) != 0);
     ctx.RESFLAG(Z80Flags.F_H | Z80Flags.F_N);
     ctx.VALFLAG(Z80Flags.F_PV, ctx.BC != 0);
 }
        public static byte doIncDec(CpuContext ctx, byte val, bool isDec)
        {
            if (isDec)
            {
                ctx.VALFLAG(Z80Flags.F_PV, ((val & 0x80) != 0) && !(((val - 1) & 0x80) != 0));
                val--;
                ctx.VALFLAG(Z80Flags.F_H, (val & 0x0F) == 0x0F);
            }
            else
            {
                ctx.VALFLAG(Z80Flags.F_PV, !((val & 0x80) != 0) && (((val + 1) & 0x80) != 0));
                val++;
                ctx.VALFLAG(Z80Flags.F_H, !((val & 0x0F) != 0));
            }

            ctx.VALFLAG(Z80Flags.F_S, ((val & 0x80) != 0));
            ctx.VALFLAG(Z80Flags.F_Z, (val == 0));
            ctx.VALFLAG(Z80Flags.F_N, isDec);

            adjustFlags(ctx, val);

            return val;
        }
 // The DAA opcode
 // According to the value in A and the flags set, add a value to A
 // This algorithm taken from:
 // http://www.worldofspectrum.org/faq/reference/z80reference.htm
 // and verified against the specification in the Zilog
 // Z80 Family CPU User Manual, rev. 04, Dec. 2004, pp. 166-167
 public static void doDAA(CpuContext ctx)
 {
     int correction_factor = 0x00;
     int carry = 0;
     if (ctx.A > 0x99 || ctx.GETFLAG(Z80Flags.F_C))
     {
         correction_factor |= 0x60;
         carry = 1;
     }
     if ((ctx.A & 0x0f) > 9 || ctx.GETFLAG(Z80Flags.F_H))
         correction_factor |= 0x06;
     int a_before = ctx.A;
     if (ctx.GETFLAG(Z80Flags.F_N))
     {
         ctx.A = (byte)(ctx.A - correction_factor);
     }
     else
     {
         ctx.A = (byte)(ctx.A + correction_factor);
     }
     ctx.VALFLAG(Z80Flags.F_H, ((a_before ^ ctx.A) & 0x10) != 0);
     ctx.VALFLAG(Z80Flags.F_C, carry != 0);
     ctx.VALFLAG(Z80Flags.F_S, (ctx.A & 0x80) != 0);
     ctx.VALFLAG(Z80Flags.F_Z, (ctx.A == 0));
     ctx.VALFLAG(Z80Flags.F_PV, parityBit[ctx.A]);
     adjustFlags(ctx, ctx.A);
 }
 public static void doCCF(CpuContext ctx)
 {
     ctx.VALFLAG(Z80Flags.F_C, (1 - (ctx.GETFLAG(Z80Flags.F_C) ? 1 : 0) != 0));
     ctx.RESFLAG(Z80Flags.F_N);
     adjustFlags(ctx, ctx.A);
 }
 public static void doBIT_r(CpuContext ctx, int Bit, byte Value)
 {
     doBIT(ctx, Bit, Value);
     ctx.VALFLAG(Z80Flags.F_5, ((Z80Flags)Value & Z80Flags.F_5) != 0);
     ctx.VALFLAG(Z80Flags.F_3, ((Z80Flags)Value & Z80Flags.F_3) != 0);
 }