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); }