コード例 #1
0
ファイル: JR.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #2
0
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction     instruction = package.Instruction;
            InstructionData data        = package.Data;

            cpu.Halt(HaltReason.HaltInstruction);

            return(new ExecutionResult(package, null));
        }
コード例 #3
0
        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));
        }
コード例 #4
0
ファイル: DAA.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #5
0
ファイル: RET.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #6
0
        public static byte MarshalSourceByte(this Instruction instruction, InstructionData data, Processor cpu, out ushort address, out ByteRegister source)
        {
            // this fetches a byte operand value for the instruction given, adjusting how it is fetched based on the addressing of the instruction

            Registers r = cpu.Registers;

            address = 0x0000;

            byte value;

            source = instruction.Source.AsByteRegister();
            if (source != ByteRegister.None)
            {
                // operand comes from another byte register directly (eg LD A,B)
                value = r[source];
            }
            else
            {
                if (instruction.Argument1 == InstructionElement.ByteValue)
                {
                    // operand is supplied as an argument (eg LD A,n)
                    value = data.Argument1;
                }
                else if (instruction.Source == InstructionElement.None)
                {
                    // operand is fetched from a memory location but the source and target are the same (eg INC (HL) or INC (IX+d))
                    address = instruction.Target.AsWordRegister() switch
                    {
                        WordRegister.IX => (ushort)(r.IX + (sbyte)data.Argument1),
                        WordRegister.IY => (ushort)(r.IY + (sbyte)data.Argument1),
                        _ => r.HL
                    };

                    value = cpu.Memory.Timed.ReadByteAt(address);
                }
                else
                {
                    // operand is fetched from a memory location and assigned elsewhere (eg LD A,(HL) or LD B,(IX+d))
                    address = instruction.Source.AsWordRegister() switch
                    {
                        WordRegister.IX => (ushort)(r.IX + (sbyte)data.Argument1),
                        WordRegister.IY => (ushort)(r.IY + (sbyte)data.Argument1),
                        _ => r.HL
                    };

                    value = cpu.Memory.Timed.ReadByteAt(address);
                }
            }

            return(value);
        }
コード例 #7
0
ファイル: RST.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #8
0
        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));
        }
コード例 #9
0
ファイル: SLL.cs プロジェクト: neilhewitt/Zem80
        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);
        }
コード例 #10
0
        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));
        }
コード例 #11
0
ファイル: BIT.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #12
0
ファイル: IN.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #13
0
        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));
        }
コード例 #14
0
ファイル: OR.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #15
0
        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));
        }
コード例 #16
0
        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));
        }
コード例 #17
0
ファイル: RRCA.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #18
0
ファイル: SET.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #19
0
        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));
        }
コード例 #20
0
ファイル: ADD.cs プロジェクト: neilhewitt/Zem80
        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));
        }
コード例 #21
0
ファイル: CP.cs プロジェクト: neilhewitt/Zem80
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction     instruction = package.Instruction;
            InstructionData data        = package.Data;
            Registers       r           = cpu.Registers;
            Flags           flags       = cpu.Flags;

            byte left = r.A;

            if (instruction.IsIndexed)
            {
                cpu.Timing.InternalOperationCycle(5);
            }
            byte right = instruction.MarshalSourceByte(data, cpu, out ushort address, out ByteRegister source);

            var sub = ALUOperations.Subtract(left, right, false);

            flags   = sub.Flags;
            flags.X = (right & 0x08) > 0; // copy bit 3 of operand, not result
            flags.Y = (right & 0x20) > 0; // copy bit 5 of operand, not result

            return(new ExecutionResult(package, flags));
        }
コード例 #22
0
        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     = (r.B == 0);
            flags.Subtract = true;
            flags.X        = (output & 0x08) > 0; // copy bit 3
            flags.Y        = (output & 0x20) > 0; // copy bit 5

            return(new ExecutionResult(package, flags));
        }
コード例 #23
0
        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 subtraction = ALUOperations.Subtract(left, right, flags.Carry, true, flags);
                r.HL  = subtraction.Result;
                flags = subtraction.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 subtraction = ALUOperations.Subtract(left, right, flags.Carry);
                r.A   = subtraction.Result;
                flags = subtraction.Flags;
            }

            return(new ExecutionResult(package, flags));
        }
コード例 #24
0
ファイル: RLD.cs プロジェクト: neilhewitt/Zem80
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction     instruction = package.Instruction;
            InstructionData data        = package.Data;
            Flags           flags       = cpu.Flags;

            byte xHL = cpu.Memory.Timed.ReadByteAt(cpu.Registers.HL);
            byte a   = cpu.Registers.A;

            // result = (HL) = LO: high-order bits of (HL) + HI: high-order bits of A
            // A = LO: low-order bits of (HL) + HI: low-order bits of A

            bool[] lowA = a.GetLowNybble();
            a   = a.SetLowNybble(xHL.GetHighNybble());
            xHL = xHL.SetHighNybble(xHL.GetLowNybble());
            xHL = xHL.SetLowNybble(lowA);

            cpu.Timing.InternalOperationCycle(4);
            cpu.Memory.Timed.WriteByteAt(cpu.Registers.HL, xHL);
            cpu.Registers.A = a;

            // bitwise flag lookup doesn't work for this instruction
            flags.Sign           = ((sbyte)a < 0);
            flags.Zero           = (a == 0);
            flags.ParityOverflow = a.EvenParity();
            flags.HalfCarry      = false;
            flags.Subtract       = false;
            flags.X = (a & 0x08) > 0; // copy bit 3
            flags.Y = (a & 0x20) > 0; // copy bit 5

            // leave carry alone

            cpu.Registers.WZ = (ushort)(cpu.Registers.HL + 1);

            return(new ExecutionResult(package, flags));
        }
コード例 #25
0
ファイル: LD.cs プロジェクト: neilhewitt/Zem80
        public ExecutionResult Execute(Processor cpu, InstructionPackage package)
        {
            Instruction     instruction = package.Instruction;
            InstructionData data        = package.Data;
            Flags           flags       = cpu.Flags;

            Registers r       = cpu.Registers;
            byte      arg0    = data.Argument1;
            byte      arg1    = data.Argument2;
            ushort    argWord = data.ArgumentsAsWord;

            byte readByte(ushort address)
            {
                return(cpu.Memory.Timed.ReadByteAt(address));
            }

            ushort readWord(ushort address)
            {
                return(cpu.Memory.Timed.ReadWordAt(address));
            }

            byte readOffset(ushort address, byte offset)
            {
                address = (ushort)(address + (sbyte)offset);
                byte value = cpu.Memory.Timed.ReadByteAt(address);

                flags.X = (address & 0x08) > 0; // copy bit 3
                flags.Y = (address & 0x20) > 0; // copy bit 5
                return(value);
            }

            void writeByte(ushort address, byte value)
            {
                cpu.Memory.Timed.WriteByteAt(address, value);
            }

            void writeWord(ushort address, ushort value)
            {
                cpu.Memory.Timed.WriteWordAt(address, value);
            }

            void writeOffset(ushort address, byte offset, byte value)
            {
                cpu.Memory.Timed.WriteByteAt((ushort)(address + (sbyte)offset), value);
            }

            void handleIRFlags(byte input)
            {
                flags.Zero = (input == 0x00);
                flags.Sign = ((sbyte)input < 0);
                flags.X    = (input & 0x08) > 0; // copy bit 3
                flags.Y    = (input & 0x20) > 0; // copy bit 5
            }

            switch (instruction.Prefix)
            {
            case 0x00:
                switch (instruction.Opcode)
                {
                case 0x01:         // LD BC,nn
                    r.BC = argWord;
                    break;

                case 0x02:         // LD (BC),A
                    writeByte(r.BC, r.A);
                    r.WZ = ((byte)((r.BC + 1) & 0xFF), r.A).ToWord();
                    break;

                case 0x06:         // LD B,n
                    r.B = arg0;
                    break;

                case 0x0A:         // LD A,(BC)
                    r.A  = readByte(r.BC);
                    r.WZ = (ushort)(r.BC + 1);
                    break;

                case 0x0E:         // LD C,n
                    r.C = arg0;
                    break;

                case 0x11:         // LD DE,nn
                    r.DE = argWord;
                    break;

                case 0x12:         // LD (DE),A
                    writeByte(r.DE, r.A);
                    r.WZ = ((byte)((r.DE + 1) & 0xFF), r.A).ToWord();
                    break;

                case 0x16:         // LD D,n
                    r.D = arg0;
                    break;

                case 0x1A:         // LD A,(DE)
                    r.A  = readByte(r.DE);
                    r.WZ = (ushort)(r.DE + 1);
                    break;

                case 0x1E:         // LD E,n
                    r.E = arg0;
                    break;

                case 0x21:         // LD HL,nn
                    r.HL = argWord;
                    break;

                case 0x22:         // LD (nn),HL
                    writeWord(argWord, r.HL);
                    break;

                case 0x26:         // LD H,n
                    r.H = arg0;
                    break;

                case 0x2A:         // LD HL,(nn)
                    r.HL = readWord(argWord);
                    break;

                case 0x2E:         // LD L,n
                    r.L = arg0;
                    break;

                case 0x31:         // LD SP,nn
                    r.SP = argWord;
                    break;

                case 0x32:         // LD (nn),A
                    writeByte(argWord, r.A);
                    r.WZ = ((byte)((argWord + 1) & 0xFF), r.A).ToWord();
                    break;

                case 0x36:         // LD (HL),n
                    writeByte(r.HL, arg0);
                    break;

                case 0x3A:         // LD A,(nn)
                    r.A  = readByte(argWord);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x3E:         // LD A,n
                    r.A = arg0;
                    break;

                case 0x40:         // LD B,B
                    r.B = r.B;     // yes, we have to do this, it's not just a NOP
                    break;

                case 0x41:         // LD B,C
                    r.B = r.C;
                    break;

                case 0x42:         // LD B,D
                    r.B = r.D;
                    break;

                case 0x43:         // LD B,E
                    r.B = r.E;
                    break;

                case 0x44:         // LD B,H
                    r.B = r.H;
                    break;

                case 0x45:         // LD B,L
                    r.B = r.L;
                    break;

                case 0x47:         // LD B,A
                    r.B = r.A;
                    break;

                case 0x46:         // LD B,(HL)
                    r.B = readByte(r.HL);
                    break;

                case 0x48:         // LD C,B
                    r.C = r.B;
                    break;

                case 0x49:         // LD C,C
                    r.C = r.C;
                    break;

                case 0x4A:         // LD C,D
                    r.C = r.D;
                    break;

                case 0x4B:         // LD C,E
                    r.C = r.E;
                    break;

                case 0x4C:         // LD C,H
                    r.C = r.H;
                    break;

                case 0x4D:         // LD C,L
                    r.C = r.L;
                    break;

                case 0x4F:         // LD C,A
                    r.C = r.A;
                    break;

                case 0x4E:         // LD C,(HL)
                    r.C = readByte(r.HL);
                    break;

                case 0x50:         // LD D,B
                    r.D = r.B;
                    break;

                case 0x51:         // LD D,C
                    r.D = r.C;
                    break;

                case 0x52:         // LD D,D
                    r.D = r.D;
                    break;

                case 0x53:         // LD D,E
                    r.D = r.E;
                    break;

                case 0x54:         // LD D,H
                    r.D = r.H;
                    break;

                case 0x55:         // LD D,L
                    r.D = r.L;
                    break;

                case 0x57:         // LD D,A
                    r.D = r.A;
                    break;

                case 0x56:         // LD D,(HL)
                    r.D = readByte(r.HL);
                    break;

                case 0x58:         // LD E,B
                    r.E = r.B;
                    break;

                case 0x59:         // LD E,C
                    r.E = r.C;
                    break;

                case 0x5A:         // LD E,D
                    r.E = r.D;
                    break;

                case 0x5B:         // LD E,E
                    r.E = r.E;
                    break;

                case 0x5C:         // LD E,H
                    r.E = r.H;
                    break;

                case 0x5D:         // LD E,L
                    r.E = r.L;
                    break;

                case 0x5F:         // LD E,A
                    r.E = r.A;
                    break;

                case 0x5E:         // LD E,(HL)
                    r.E = readByte(r.HL);
                    break;

                case 0x60:         // LD H,B
                    r.H = r.B;
                    break;

                case 0x61:         // LD H,C
                    r.H = r.C;
                    break;

                case 0x62:         // LD H,D
                    r.H = r.D;
                    break;

                case 0x63:         // LD H,E
                    r.H = r.E;
                    break;

                case 0x64:         // LD H,H
                    r.H = r.H;
                    break;

                case 0x65:         // LD H,L
                    r.H = r.L;
                    break;

                case 0x67:         // LD H,A
                    r.H = r.A;
                    break;

                case 0x66:         // LD H,(HL)
                    r.H = readByte(r.HL);
                    break;

                case 0x68:         // LD L,B
                    r.L = r.B;
                    break;

                case 0x69:         // LD L,C
                    r.L = r.C;
                    break;

                case 0x6A:         // LD L,D
                    r.L = r.D;
                    break;

                case 0x6B:         // LD L,E
                    r.L = r.E;
                    break;

                case 0x6C:         // LD L,H
                    r.L = r.H;
                    break;

                case 0x6D:         // LD L,L
                    r.L = r.L;
                    break;

                case 0x6F:         // LD L,A
                    r.L = r.A;
                    break;

                case 0x6E:         // LD L,(HL)
                    r.L = readByte(r.HL);
                    break;

                case 0x70:         // LD (HL),B
                    writeByte(r.HL, r.B);
                    break;

                case 0x71:         // LD (HL),C
                    writeByte(r.HL, r.C);
                    break;

                case 0x72:         // LD (HL),D
                    writeByte(r.HL, r.D);
                    break;

                case 0x73:         // LD (HL),E
                    writeByte(r.HL, r.E);
                    break;

                case 0x74:         // LD (HL),H
                    writeByte(r.HL, r.H);
                    break;

                case 0x75:         // LD (HL),L
                    writeByte(r.HL, r.L);
                    break;

                case 0x77:         // LD (HL),A
                    writeByte(r.HL, r.A);
                    break;

                case 0x78:         // LD A,B
                    r.A = r.B;
                    break;

                case 0x79:         // LD A,C
                    r.A = r.C;
                    break;

                case 0x7A:         // LD A,D
                    r.A = r.D;
                    break;

                case 0x7B:         // LD A,E
                    r.A = r.E;
                    break;

                case 0x7C:         // LD A,H
                    r.A = r.H;
                    break;

                case 0x7D:         // LD A,L
                    r.A = r.L;
                    break;

                case 0x7F:         // LD A,A
                    r.A = r.A;
                    break;

                case 0x7E:         // LD A,(HL)
                    r.A = readByte(r.HL);
                    break;

                case 0xF9:         // LD SP,HL
                    r.SP = r.HL;
                    break;
                }
                break;

            case 0xED:
                switch (instruction.Opcode)
                {
                case 0x43:         // LD (nn),BC
                    writeWord(argWord, r.BC);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x47:         // LD I,A
                    r.I = r.A;
                    handleIRFlags(r.A);
                    break;

                case 0x4B:         // LD BC,(nn)
                    r.BC = readWord(argWord);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x4F:         // LD R,A
                    r.R = r.A;
                    handleIRFlags(r.A);
                    break;

                case 0x53:         // LD (nn),DE
                    writeWord(argWord, r.DE);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x57:         // LD A,I
                    r.A = r.I;
                    handleIRFlags(r.A);
                    flags.ParityOverflow = cpu.InterruptsPaused;
                    break;

                case 0x5B:         // LD DE,(nn)
                    r.DE = readWord(argWord);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x5F:         // LD A,R
                    r.A = r.R;
                    handleIRFlags(r.A);
                    flags.ParityOverflow = cpu.InterruptsPaused;
                    break;

                case 0x73:         // LD (nn),SP
                    writeWord(argWord, r.SP);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x7B:         // LD SP,(nn)
                    r.SP = readWord(argWord);
                    r.WZ = (ushort)(argWord + 1);
                    break;
                }
                break;

            case 0xDD:
                switch (instruction.Opcode)
                {
                case 0x21:         // LD IX,nn
                    r.IX = argWord;
                    break;

                case 0x22:         // LD (nn),IX
                    writeWord(argWord, r.IX);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x26:         // LD IXh,n
                    r.IXh = arg0;
                    break;

                case 0x2A:         // LD IX,(nn)
                    r.IX = readWord(argWord);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x2E:         // LD IXl,n
                    r.IXl = arg0;
                    break;

                case 0x36:         // LD (IX+o),n
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IX, arg0, arg1);
                    break;

                case 0x44:         // LD B,IXh
                    r.B = r.IXh;
                    break;

                case 0x45:         // LD B,IXl
                    r.B = r.IXl;
                    break;

                case 0x46:         // LD B,(IX+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.B = readOffset(r.IX, arg0);
                    break;

                case 0x4C:         // LD C,IXh
                    r.C = r.IXh;
                    break;

                case 0x4D:         // LD C,IXl
                    r.C = r.IXl;
                    break;

                case 0x4E:         // LD C,(IX+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.C = readOffset(r.IX, arg0);
                    break;

                case 0x54:         // LD D,IXh
                    r.D = r.IXh;
                    break;

                case 0x55:         // LD D,IXl
                    r.D = r.IXl;
                    break;

                case 0x56:         // LD D,(IX+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.D = readOffset(r.IX, arg0);
                    break;

                case 0x5C:         // LD E,IXh
                    r.E = r.IXh;
                    break;

                case 0x5D:         // LD E,IXl
                    r.E = r.IXl;
                    break;

                case 0x5E:         // LD E,(IX+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.E = readOffset(r.IX, arg0);
                    break;

                case 0x60:         // LD IXh,B
                    r.IXh = r.B;
                    break;

                case 0x61:         // LD IXh,C
                    r.IXh = r.C;
                    break;

                case 0x62:         // LD IXh,D
                    r.IXh = r.D;
                    break;

                case 0x63:         // LD IXh,E
                    r.IXh = r.E;
                    break;

                case 0x64:         // LD IXh,IXh
                    r.IXh = r.IXh;
                    break;

                case 0x65:         // LD IXh,IXl
                    r.IXh = r.IXl;
                    break;

                case 0x67:         // LD IXh,A
                    r.IXh = r.A;
                    break;

                case 0x66:         // LD H,(IX+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.H = readOffset(r.IX, arg0);
                    break;

                case 0x68:         // LD IXl,B
                    r.IXl = r.B;
                    break;

                case 0x69:         // LD IXl,C
                    r.IXl = r.C;
                    break;

                case 0x6A:         // LD IXl,D
                    r.IXl = r.D;
                    break;

                case 0x6B:         // LD IXl,E
                    r.IXl = r.E;
                    break;

                case 0x6C:         // LD IXl,IXh
                    r.IXl = r.IXh;
                    break;

                case 0x6D:         // LD IXl,IXl
                    r.IXl = r.IXl;
                    break;

                case 0x6F:         // LD IXl,A
                    r.IXl = r.A;
                    break;

                case 0x6E:         // LD L,(IX+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.L = readOffset(r.IX, arg0);
                    break;

                case 0x70:         // LD (IX+o),B
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IX, arg0, r.B);
                    break;

                case 0x71:         // LD (IX+o),C
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IX, arg0, r.C);
                    break;

                case 0x72:         // LD (IX+o),D
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IX, arg0, r.D);
                    break;

                case 0x73:         // LD (IX+o),E
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IX, arg0, r.E);
                    break;

                case 0x74:         // LD (IX+o),H
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IX, arg0, r.H);
                    break;

                case 0x75:         // LD (IX+o),L
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IX, arg0, r.L);
                    break;

                case 0x77:         // LD (IX+o),A
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IX, arg0, r.A);
                    break;

                case 0x7C:         // LD A,IXh
                    r.A = r.IXh;
                    break;

                case 0x7D:         // LD A,IXl
                    r.A = r.IXl;
                    break;

                case 0x7E:         // LD A,(IX+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.A = readOffset(r.IX, arg0);
                    break;

                case 0xF9:         // LD SP,IX
                    r.SP = r.IX;
                    break;
                }
                break;

            case 0xFD:
                switch (instruction.Opcode)
                {
                case 0x21:         // LD IY,nn
                    r.IY = argWord;
                    break;

                case 0x22:         // LD (nn),IY
                    writeWord(argWord, r.IY);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x26:         // LD IYh,n
                    r.IYh = arg0;
                    break;

                case 0x2A:         // LD IY,(nn)
                    r.IY = readWord(argWord);
                    r.WZ = (ushort)(argWord + 1);
                    break;

                case 0x2E:         // LD IYl,n
                    r.IYl = arg0;
                    break;

                case 0x36:         // LD (IY+o),n
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IY, arg0, arg1);
                    break;

                case 0x44:         // LD B,IYh
                    r.B = r.IYh;
                    break;

                case 0x45:         // LD B,IYl
                    r.B = r.IYl;
                    break;

                case 0x46:         // LD B,(IY+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.B = readOffset(r.IY, arg0);
                    break;

                case 0x4C:         // LD C,IYh
                    r.C = r.IYh;
                    break;

                case 0x4D:         // LD C,IYl
                    r.C = r.IYl;
                    break;

                case 0x4E:         // LD C,(IY+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.C = readOffset(r.IY, arg0);
                    break;

                case 0x54:         // LD D,IYh
                    r.D = r.IYh;
                    break;

                case 0x55:         // LD D,IYl
                    r.D = r.IYl;
                    break;

                case 0x56:         // LD D,(IY+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.D = readOffset(r.IY, arg0);
                    break;

                case 0x5C:         // LD E,IYh
                    r.E = r.IYh;
                    break;

                case 0x5D:         // LD E,IYl
                    r.E = r.IYl;
                    break;

                case 0x5E:         // LD E,(IY+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.E = readOffset(r.IY, arg0);
                    break;

                case 0x60:         // LD IYh,B
                    r.IYh = r.B;
                    break;

                case 0x61:         // LD IYh,C
                    r.IYh = r.C;
                    break;

                case 0x62:         // LD IYh,D
                    r.IYh = r.D;
                    break;

                case 0x63:         // LD IYh,E
                    r.IYh = r.E;
                    break;

                case 0x64:         // LD IYh,IYh
                    r.IYh = r.IYh;
                    break;

                case 0x65:         // LD IYh,IYl
                    r.IYh = r.IYl;
                    break;

                case 0x67:         // LD IYh,A
                    r.IYh = r.A;
                    break;

                case 0x66:         // LD H,(IY+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.H = readOffset(r.IY, arg0);
                    break;

                case 0x68:         // LD IYl,B
                    r.IYl = r.B;
                    break;

                case 0x69:         // LD IYl,C
                    r.IYl = r.C;
                    break;

                case 0x6A:         // LD IYl,D
                    r.IYl = r.D;
                    break;

                case 0x6B:         // LD IYl,E
                    r.IYl = r.E;
                    break;

                case 0x6C:         // LD IYl,IYh
                    r.IYl = r.IYh;
                    break;

                case 0x6D:         // LD IYl,IYl
                    r.IYl = r.IYl;
                    break;

                case 0x6F:         // LD IYl,A
                    r.IYl = r.A;
                    break;

                case 0x6E:         // LD L,(IY+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.L = readOffset(r.IY, arg0);
                    break;

                case 0x70:         // LD (IY+o),B
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IY, arg0, r.B);
                    break;

                case 0x71:         // LD (IY+o),C
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IY, arg0, r.C);
                    break;

                case 0x72:         // LD (IY+o),D
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IY, arg0, r.D);
                    break;

                case 0x73:         // LD (IY+o),E
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IY, arg0, r.E);
                    break;

                case 0x74:         // LD (IY+o),H
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IY, arg0, r.H);
                    break;

                case 0x75:         // LD (IY+o),L
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IY, arg0, r.L);
                    break;

                case 0x77:         // LD (IY+o),A
                    cpu.Timing.InternalOperationCycle(5);
                    writeOffset(r.IY, arg0, r.A);
                    break;

                case 0x7C:         // LD A,IYh
                    r.A = r.IYh;
                    break;

                case 0x7D:         // LD A,IYl
                    r.A = r.IYl;
                    break;

                case 0x7E:         // LD A,(IY+o)
                    cpu.Timing.InternalOperationCycle(5);
                    r.A = readOffset(r.IY, arg0);
                    break;

                case 0xF9:         // LD SP,IY
                    r.SP = r.IY;
                    break;
                }
                break;
            }

            return(new ExecutionResult(package, flags));
        }
コード例 #26
0
 public InstructionPackage(Instruction instruction, InstructionData data, ushort instructionAddress)
 {
     Instruction        = instruction;
     Data               = data;
     InstructionAddress = instructionAddress;
 }