public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; void @out(byte portNumber, ByteRegister dataRegister, bool bc) { Port port = cpu.Ports[portNumber]; byte output = 0; if (dataRegister != ByteRegister.None) { output = r[dataRegister]; } port.SignalWrite(); port.WriteByte(output, bc); } if (instruction.Prefix == 0x00) { // OUT (n),A r.WZ = (ushort)((r.A << 8) + data.Argument1 + 1); @out(data.Argument1, ByteRegister.A, false); } else { // OUT (C),r @out(r.C, instruction.Source.AsByteRegister(), true); r.WZ = (ushort)(r.BC + 1); } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; Port port = cpu.Ports[r.C]; port.SignalRead(); byte input = port.ReadByte(true); cpu.Memory.Timed.WriteByteAt(r.HL, input); cpu.Timing.InternalOperationCycle(5); r.HL--; r.WZ = r.BC; r.B--; flags.Zero = true; flags.Subtract = true; flags.X = (input & 0x08) > 0; // copy bit 3 flags.Y = (input & 0x20) > 0; // copy bit 5 if (r.B != 0) { r.PC = package.InstructionAddress; } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; switch (instruction.Opcode) { case 0x46: case 0x4E: case 0x66: // IM 0 cpu.SetInterruptMode(InterruptMode.IM0); break; case 0x56: case 0x76: // IM 1 cpu.SetInterruptMode(InterruptMode.IM1); break; case 0x5E: case 0x7E: // IM 2 cpu.SetInterruptMode(InterruptMode.IM2); break; } return(new ExecutionResult(package, null)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; byte value = cpu.Memory.Timed.ReadByteAt(r.HL); cpu.Memory.Timed.WriteByteAt(r.DE, value); r.HL++; r.DE++; r.BC--; flags.HalfCarry = false; flags.ParityOverflow = (r.BC != 0);; flags.Subtract = false; flags.X = (((byte)(value + cpu.Registers.A)) & 0x08) > 0; // copy bit 3 flags.Y = (((byte)(value + cpu.Registers.A)) & 0x02) > 0; // copy bit 1 (note: non-standard behaviour) bool conditionTrue = (r.BC == 0); if (conditionTrue) { cpu.Timing.InternalOperationCycle(5); r.WZ = (ushort)(r.PC + 1); } else { r.PC = package.InstructionAddress; } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { cpu.Pop(WordRegister.PC); cpu.Registers.WZ = cpu.Registers.PC; cpu.RestoreInterruptsFromNMI(); // will re-enable maskable interrupts if they were enabled before entering the NMI handler return(new ExecutionResult(package, null)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Registers r = cpu.Registers; if (instruction.Opcode == 0x08) { // EX AF,AF' r.ExchangeAF(); } else { if (instruction.Target == InstructionElement.AddressFromSP) { // EX (SP),HL/IX/IY ushort value = instruction.MarshalSourceWord(data, cpu, out ushort address); ushort valueAtSP = cpu.Memory.Untimed.ReadWordAt(r.SP); r[instruction.Source.AsWordRegister()] = valueAtSP; cpu.Memory.Timed.WriteWordAt(r.SP, value); r.WZ = valueAtSP; } else { // EX DE,HL ushort de = r.DE; r.DE = r.HL; r.HL = de; } } return(new ExecutionResult(package, null)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; if (instruction.TargetsWordRegister) { ushort left = r.HL; cpu.Timing.InternalOperationCycle(4); cpu.Timing.InternalOperationCycle(3); ushort right = instruction.MarshalSourceWord(data, cpu, out ushort address); var addition = ALUOperations.Add(left, right, flags.Carry, true, flags); r.HL = addition.Result; flags = addition.Flags; r.WZ = (ushort)(left + 1); } else { byte left = r.A; if (instruction.IsIndexed) { cpu.Timing.InternalOperationCycle(5); } byte right = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source); var addition = ALUOperations.Add(left, right, flags.Carry); r.A = addition.Result; flags = addition.Flags; } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; Port port = cpu.Ports[r.C]; byte output = cpu.Memory.Timed.ReadByteAt(r.HL); r.WZ = r.BC; r.B--; port.SignalWrite(); port.WriteByte(output, true); r.HL++; flags.Zero = true; flags.Subtract = true; flags.X = (output & 0x08) > 0; // copy bit 3 flags.Y = (output & 0x20) > 0; // copy bit 5 if (r.B != 0) { r.PC = package.InstructionAddress; } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; bool carry = flags.Carry; byte a = cpu.Registers.A; byte b = cpu.Memory.Timed.ReadByteAt(cpu.Registers.HL); var compare = ALUOperations.Subtract(a, b, false); flags = compare.Flags; cpu.Registers.BC--; flags.ParityOverflow = (cpu.Registers.BC != 0); cpu.Registers.HL--; flags.Subtract = true; flags.Carry = carry; byte valueXY = (byte)(a - b - (flags.HalfCarry ? 1 : 0)); flags.X = (valueXY & 0x08) > 0; // copy bit 3 flags.Y = (valueXY & 0x02) > 0; // copy bit 1 (note: non-standard behaviour) cpu.Registers.WZ++; return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; if (instruction.Condition == Condition.None || cpu.Flags.SatisfyCondition(instruction.Condition)) { cpu.Timing.InternalOperationCycle(5); ushort address = (ushort)(cpu.Registers.PC - 2); // wind back to the address of the JR instruction as PC has already moved on // the jump is relative to the address of the JR instruction but the jump *displacement* is calculated from the start of the *next* instruction. // This means the actual jump range is -126 to +129 bytes, *not* 127 bytes each way. Z80 assemblers compensate for this by // adjusting the jump value, so for example 'JR 0' would actually end up being 'JR 2' and would set PC to the start of the next // instruction - hence we must add two bytes here to resolve the correct target address address = (ushort)(address + (sbyte)data.Argument1 + 2); cpu.Registers.PC = address; cpu.Flags.X = (address & 0x08) > 0; // copy bit 3 cpu.Flags.Y = (address & 0x20) > 0; // copy bit 5 cpu.Registers.WZ = address; } return(new ExecutionResult(package, cpu.Flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; cpu.Halt(HaltReason.HaltInstruction); return(new ExecutionResult(package, null)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; WordRegister register = instruction.Target.AsWordRegister(); cpu.Pop(register); return(new ExecutionResult(package, null)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; sbyte offset = (sbyte)(data.Argument1); ByteRegister register = instruction.Target.AsByteRegister(); bool previousCarry = flags.Carry; byte original, shifted; if (register != ByteRegister.None) { original = r[register]; shifted = (byte)(original >> 1); shifted = shifted.SetBit(7, previousCarry); setFlags(original, shifted, original.GetBit(0)); r[register] = shifted; } else { ushort address = instruction.Prefix switch { 0xCB => r.HL, 0xDDCB => (ushort)(r.IX + offset), 0xFDCB => (ushort)(r.IY + offset), _ => (ushort)0xFFFF }; original = cpu.Memory.Timed.ReadByteAt(address); shifted = (byte)(original >> 1); shifted = shifted.SetBit(7, previousCarry); setFlags(original, shifted, original.GetBit(0)); if (instruction.IsIndexed) { cpu.Timing.InternalOperationCycle(4); } cpu.Memory.Timed.WriteByteAt(address, shifted); if (instruction.CopyResultTo != ByteRegister.None) { r[instruction.CopyResultTo.Value] = shifted; } } void setFlags(byte original, byte shifted, bool overflowBit) { flags = FlagLookup.BitwiseFlags(original, BitwiseOperation.RotateRightThroughCarry, previousCarry); flags.Carry = overflowBit; flags.HalfCarry = false; flags.Subtract = false; } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; byte A = r.A; int mode = 0; if ((A & 0x0F) > 0x09 || flags.HalfCarry) { mode++; } if (A > 0x99 || flags.Carry) { mode += 2; flags.Carry = true; } if (flags.Subtract && !flags.HalfCarry) { flags.HalfCarry = false; } else { if (flags.Subtract && flags.HalfCarry) { flags.HalfCarry = (A & 0x0F) < 0x06; } else { flags.HalfCarry = (A & 0x0F) >= 0x0A; } } A = mode switch { 1 => (byte)(A + (byte)(flags.Subtract ? 0xFA : 0x06)), 2 => (byte)(A + (byte)(flags.Subtract ? 0xA0 : 0x60)), 3 => (byte)(A + (byte)(flags.Subtract ? 0x9A : 0x66)), _ => A }; flags.Sign = (A & 0x80) > 0; flags.Zero = (A == 0); flags.ParityOverflow = A.EvenParity(); flags.X = (A & 0x08) > 0; // copy bit 3 flags.Y = (A & 0x20) > 0; // copy bit 5 r.A = A; return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Flags flags = cpu.Flags; flags.Carry = true; flags.HalfCarry = false; flags.Subtract = false; flags.X = (cpu.Registers.A & 0x08) > 0; // copy bit 3 flags.Y = (cpu.Registers.A & 0x20) > 0; // copy bit 5 return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; if (instruction.Condition == Condition.None || flags.SatisfyCondition(instruction.Condition)) { cpu.Pop(WordRegister.PC); cpu.Registers.WZ = cpu.Registers.PC; } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; byte t_index = instruction.Opcode.GetByteFromBits(3, 3); ushort address = (ushort)(t_index * 8); cpu.Push(WordRegister.PC); cpu.Registers.PC = (address); cpu.Registers.WZ = cpu.Registers.PC; return(new ExecutionResult(package, null)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Registers r = cpu.Registers; Flags flags = cpu.Flags; int result = 0x00 - r.A; flags = FlagLookup.ByteArithmeticFlags(0x00, r.A, false, true); flags.ParityOverflow = r.A == 0x80; flags.Carry = r.A != 0x00; r.A = (byte)result; return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; sbyte offset = (sbyte)(data.Argument1); ByteRegister register = instruction.Target.AsByteRegister(); void setFlags(byte original) { flags = FlagLookup.BitwiseFlags(original, BitwiseOperation.ShiftLeftSetBit0, flags.Carry); flags.Carry = original.GetBit(7); flags.HalfCarry = false; flags.Subtract = false; } byte original, shifted; if (register != ByteRegister.None) { original = r[register]; shifted = (byte)((original << 1) + 1); // bit 0 is always set, adding 1 does this quicker than calling SetBit setFlags(original); r[register] = shifted; } else { ushort address = instruction.Prefix switch { 0xCB => r.HL, 0xDDCB => (ushort)(r.IX + offset), 0xFDCB => (ushort)(r.IY + offset), _ => (ushort)0xFFFF }; original = cpu.Memory.Timed.ReadByteAt(address); shifted = (byte)((original << 1) + 1); setFlags(original); cpu.Memory.Timed.WriteByteAt(address, shifted); if (instruction.CopyResultTo != ByteRegister.None) { r[instruction.CopyResultTo.Value] = shifted; } } return new ExecutionResult(package, flags); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Registers r = cpu.Registers; byte offset = data.Argument1; Flags flags = cpu.Flags; if (instruction.TargetsWordRegister) { // inc 16-bit WordRegister register = instruction.Target.AsWordRegister(); ushort value = r[register]; r[register] = (ushort)(value + 1); } else { byte value = 0; if (instruction.TargetsByteInMemory) { // inc byte in memory if (instruction.IsIndexed) { cpu.Timing.InternalOperationCycle(5); } value = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source); cpu.Memory.Timed.WriteByteAt(address, (byte)(value + 1)); } else { // it's an 8-bit inc ByteRegister register = instruction.Target.AsByteRegister(); value = r[register]; r[register] = (byte)(value + 1); } bool carry = flags.Carry; flags = FlagLookup.ByteArithmeticFlags(value, 1, false, false); flags.ParityOverflow = (value == 0x7F); flags.Carry = carry; // always unaffected flags.Subtract = false; } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Registers r = cpu.Registers; Flags flags = cpu.Flags; byte bitIndex = instruction.GetBitIndex(); byte value; ByteRegister register = instruction.Source.AsByteRegister(); if (register != ByteRegister.None) { value = r[register]; // BIT b, r } else { if (instruction.IsIndexed) { cpu.Timing.InternalOperationCycle(5); } value = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source); byte valueXY = instruction.IsIndexed ? address.HighByte() : r.WZ.HighByte(); // this is literally the only place the WZ value is *ever* actually used flags.X = (valueXY & 0x08) > 0; // copy bit 3 flags.Y = (valueXY & 0x20) > 0; // copy bit 5 } bool set = value.GetBit(bitIndex); flags.Sign = bitIndex == 7 && set; if (register == ByteRegister.None) { flags.Y = bitIndex == 5 && set; flags.X = bitIndex == 3 && set; } flags.Zero = !set; flags.ParityOverflow = flags.Zero; flags.HalfCarry = true; flags.Subtract = false; return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; if (instruction.Source != InstructionElement.WordValue) { // JP HL / IX / IY cpu.Registers.PC = instruction.MarshalSourceWord(data, cpu, out ushort address); } else if (instruction.Condition == Condition.None || flags.SatisfyCondition(instruction.Condition)) { cpu.Registers.PC = data.ArgumentsAsWord; cpu.Registers.WZ = data.ArgumentsAsWord; } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; if (instruction.IsIndexed) { cpu.Timing.InternalOperationCycle(5); } byte operand = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source); int result = (r.A | operand); flags = FlagLookup.LogicalFlags(r.A, operand, LogicalOperation.Or); r.A = (byte)result; return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; byte @in(byte portNumber, ByteRegister toRegister, bool bc) { Port port = cpu.Ports[portNumber]; port.SignalRead(); byte input = port.ReadByte(bc); if (toRegister != ByteRegister.F) { r[toRegister] = input; } return(input); } if (instruction.Prefix == 0x00) { // IN A,(n) r.WZ = (ushort)((r.A << 8) + data.Argument1 + 1); @in(data.Argument1, ByteRegister.A, false); } else { // IN r,(C) byte input = @in(r.C, instruction.Target.AsByteRegister(), true); flags.Sign = ((sbyte)input < 0); flags.Zero = (input == 0); flags.ParityOverflow = input.EvenParity(); flags.HalfCarry = false; flags.Subtract = false; flags.X = (input & 0x08) > 0; // copy bit 3 flags.Y = (input & 0x20) > 0; // copy bit 5 r.WZ = (ushort)(r.BC + 1); } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; bool carry = flags.Carry; byte a = cpu.Registers.A; byte b = cpu.Memory.Timed.ReadByteAt(cpu.Registers.HL); var compare = ALUOperations.Subtract(a, b, false); flags = compare.Flags; cpu.Registers.BC--; flags.ParityOverflow = (cpu.Registers.BC != 0); cpu.Registers.HL++; flags.Subtract = true; flags.Carry = carry; byte valueXY = (byte)(a - b - (flags.HalfCarry ? 1 : 0)); flags.X = (valueXY & 0x08) > 0; // copy bit 3 flags.Y = (valueXY & 0x02) > 0; // copy bit 1 (note: non-standard behaviour) bool conditionTrue = (compare.Result == 0 || cpu.Registers.BC == 0); if (conditionTrue) { cpu.Timing.InternalOperationCycle(5); cpu.Registers.WZ++; } else { cpu.Registers.PC = package.InstructionAddress; cpu.Registers.WZ = (ushort)(cpu.Registers.PC + 1); } return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; byte value = r.A; flags.Carry = value.GetBit(0); value = (byte)(value >> 1); value = value.SetBit(7, flags.Carry); flags.HalfCarry = false; flags.Subtract = false; flags.X = (value & 0x08) > 0; // copy bit 3 flags.Y = (value & 0x20) > 0; // copy bit 5 r.A = value; return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; byte left = r.A; byte right = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source); if (instruction.IsIndexed) { cpu.Timing.InternalOperationCycle(5); } var sub = ALUOperations.Subtract(left, right, false); r.A = sub.Result; flags = sub.Flags; return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Registers r = cpu.Registers; byte bitIndex = instruction.GetBitIndex(); sbyte offset = (sbyte)(data.Argument1); ByteRegister register = instruction.Source.AsByteRegister(); if (register != ByteRegister.None) { byte value = r[register].SetBit(bitIndex, true); r[register] = value; } else { ushort address = instruction.Prefix switch { 0xCB => r.HL, 0xDDCB => (ushort)(r.IX + offset), 0xFDCB => (ushort)(r.IY + offset), _ => (ushort)0xFFFF }; if (instruction.IsIndexed) { cpu.Timing.InternalOperationCycle(5); } byte value = cpu.Memory.Timed.ReadByteAt(address); value = value.SetBit(bitIndex, true); cpu.Memory.Timed.WriteByteAt(address, value); if (instruction.CopyResultTo != ByteRegister.None) { r[instruction.CopyResultTo.Value] = value; } } return(new ExecutionResult(package, null)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; byte value = cpu.Memory.Timed.ReadByteAt(r.HL); cpu.Memory.Timed.WriteByteAt(r.DE, value); r.HL++; r.DE++; r.BC--; flags.HalfCarry = false; flags.ParityOverflow = (r.BC != 0); flags.Subtract = false; flags.X = (((byte)(value + cpu.Registers.A)) & 0x08) > 0; // copy bit 3 flags.Y = (((byte)(value + cpu.Registers.A)) & 0x02) > 0; // copy bit 1 (note: non-standard behaviour) return(new ExecutionResult(package, flags)); }
public ExecutionResult Execute(Processor cpu, InstructionPackage package) { Instruction instruction = package.Instruction; InstructionData data = package.Data; Flags flags = cpu.Flags; Registers r = cpu.Registers; if (instruction.TargetsWordRegister) { // it's one of the 16-bit adds (HL,DE etc) WordRegister destination = instruction.Target.AsWordRegister(); ushort left = r[destination]; ushort right = instruction.MarshalSourceWord(data, cpu, out ushort address); cpu.Timing.InternalOperationCycle(4); cpu.Timing.InternalOperationCycle(3); var sum = ALUOperations.Add(left, right, false, false, flags); r[destination] = sum.Result; flags = sum.Flags; r.WZ = (ushort)(left + 1); } else { // it's an 8-bit add to A byte left = r.A; if (instruction.IsIndexed) { cpu.Timing.InternalOperationCycle(5); } byte right = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source); var sum = ALUOperations.Add(left, right, false); r.A = sum.Result; flags = sum.Flags; } return(new ExecutionResult(package, flags)); }