1711 lines
54 KiB
C#
1711 lines
54 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace MCEmuCore.GBMonolith
|
|
{
|
|
public struct OpCode
|
|
{
|
|
public readonly byte Instruction;
|
|
public byte? Arg1;
|
|
public byte? Arg2;
|
|
}
|
|
class Cpu
|
|
{
|
|
private readonly CpuRegisters registers;
|
|
private bool halted = false;
|
|
private bool interruptsEnabled = true;
|
|
private IMemory memory;
|
|
#region OpCodes
|
|
|
|
private readonly List<Func<OpCode, int>> OpCodeArray;
|
|
#endregion
|
|
|
|
public Cpu()
|
|
{
|
|
registers = new CpuRegisters();
|
|
|
|
OpCodeArray = new List<Func<OpCode, int>>()
|
|
{
|
|
#region OpCodes
|
|
#region OpCodes 0x00-0x0F
|
|
// 0x00
|
|
(op) => {
|
|
// NOP
|
|
return 4;
|
|
},
|
|
// 0x01
|
|
(op) => {
|
|
// LD BC,d16
|
|
registers.BC = ReadShortFromInstruction();
|
|
return 12;
|
|
},
|
|
// 0x02
|
|
(op) => {
|
|
// LD (BC), A
|
|
memory.WriteByte(0xFF00 + registers.BC, registers.A);
|
|
return 8;
|
|
},
|
|
// 0x03
|
|
(op) => {
|
|
registers.BC += 1;
|
|
return 8;
|
|
},
|
|
// 0x04
|
|
(op) => {
|
|
// INC B
|
|
registers.B = IncrementRegister(registers.B);
|
|
|
|
return 4;
|
|
},
|
|
// 0x05
|
|
(op) => {
|
|
// DEC B
|
|
registers.B = DecrementRegister(registers.B);
|
|
|
|
return 4;
|
|
},
|
|
// 0x06
|
|
(op) => {
|
|
// LD B,d8
|
|
registers.B = ReadInstruction();
|
|
return 8;
|
|
},
|
|
// 0x07
|
|
(op) => {
|
|
// RLCA
|
|
registers.Flags.Zero = false;
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.Carry = (registers.A & 0b1000_0000) != 0;
|
|
|
|
registers.A = (byte)((registers.A << 1) + (registers.A >> 7));
|
|
return 4;
|
|
},
|
|
// 0x08
|
|
(op) => {
|
|
// LD (a16), SP
|
|
// Load SP into address
|
|
int address = ReadShortFromInstruction();
|
|
memory.WriteShort(address, registers.SP);
|
|
return 20;
|
|
},
|
|
// 0x09
|
|
(op) => {
|
|
// ADD HL, BC
|
|
registers.HL = AddWideRegisters(registers.HL, registers.BC);
|
|
|
|
return 8;
|
|
},
|
|
// 0x0A
|
|
(op) => {
|
|
// LD A, (BC)
|
|
// Load byte at address stored in BC into A
|
|
registers.A = memory.ReadByte(0xFF + registers.BC);
|
|
return 8;
|
|
},
|
|
// 0x0B
|
|
(op) => {
|
|
// DEC BC
|
|
registers.BC -= 1;
|
|
return 8;
|
|
},
|
|
// 0x0C
|
|
(op) => {
|
|
// INC C
|
|
registers.C = IncrementRegister(registers.C);
|
|
|
|
return 4;
|
|
},
|
|
// 0x0D
|
|
(op) => {
|
|
// DEC C
|
|
registers.C = DecrementRegister(registers.C);
|
|
|
|
return 4;
|
|
},
|
|
// 0x0E
|
|
(op) => {
|
|
// LD C,d8
|
|
registers.C = ReadInstruction();
|
|
return 8;
|
|
},
|
|
// 0x0F
|
|
(op) => {
|
|
// RRCA
|
|
registers.Flags.Zero = false;
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.Carry = (registers.A & 0b0000_0001) != 0;
|
|
|
|
registers.A = (byte)((registers.A >> 1) + (registers.A << 7));
|
|
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x10-0x1F
|
|
// 0x10
|
|
(op) => {
|
|
// STOP 0
|
|
// Halts CPU & LCD until button pressed
|
|
throw new NotImplementedException("STOP");
|
|
},
|
|
// 0x11
|
|
(op) => {
|
|
// LD DE, d16
|
|
registers.DE = ReadShortFromInstruction();
|
|
return 12;
|
|
},
|
|
// 0x12
|
|
(op) => {
|
|
// LD (DE), A
|
|
memory.WriteByte(0xFF00 + registers.DE, registers.A);
|
|
return 8;
|
|
},
|
|
// 0x13
|
|
(op) => {
|
|
// INC DE
|
|
registers.DE += 1;
|
|
return 8;
|
|
},
|
|
// 0x14
|
|
(op) => {
|
|
registers.D = IncrementRegister(registers.D);
|
|
|
|
return 4;
|
|
},
|
|
// 0x15
|
|
(op) => {
|
|
registers.D = DecrementRegister(registers.D);
|
|
|
|
return 4;
|
|
},
|
|
// 0x16
|
|
(op) => {
|
|
registers.D = ReadInstruction();
|
|
return 8;
|
|
},
|
|
// 0x17
|
|
(op) => {
|
|
// RLA
|
|
int carryBit = registers.Flags.Carry ? 1 : 0;
|
|
|
|
registers.Flags.Zero = false;
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.Carry = (registers.A & 0b1000_0000) != 0;
|
|
|
|
registers.A = (byte)((registers.A << 1) + carryBit);
|
|
return 4;
|
|
},
|
|
// 0x18
|
|
(op) => {
|
|
byte jump = ReadInstruction();
|
|
registers.PC += jump;
|
|
return 12;
|
|
},
|
|
// 0x19
|
|
(op) => {
|
|
// ADD HL, DE
|
|
registers.HL = AddWideRegisters(registers.HL, registers.DE);
|
|
|
|
return 8;
|
|
},
|
|
// 0x1A
|
|
(op) => {
|
|
// LD A, (DE)
|
|
// Load byte at address stored in DE into A
|
|
byte val = memory.ReadByte(registers.DE);
|
|
registers.A = val;
|
|
return 8;
|
|
},
|
|
// 0x1B
|
|
(op) => {
|
|
// DEC DE
|
|
registers.DE -= 1;
|
|
|
|
return 8;
|
|
},
|
|
// 0x1C
|
|
(op) => {
|
|
registers.E = IncrementRegister(registers.E);
|
|
|
|
return 4;
|
|
},
|
|
// 0x1D
|
|
(op) => {
|
|
registers.E = IncrementRegister(registers.E);
|
|
|
|
return 4;
|
|
},
|
|
// 0x1E
|
|
(op) => {
|
|
registers.E = ReadInstruction();
|
|
return 8;
|
|
},
|
|
// 0x1F
|
|
(op) => {
|
|
// RRA
|
|
int carryBit = registers.Flags.Carry ? 1 : 0;
|
|
|
|
registers.Flags.Zero = false;
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.Carry = (registers.A & 0b0000_0001) != 0;
|
|
|
|
registers.A = (byte)((registers.A >> 1) + (carryBit << 7));
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x20-0x2F
|
|
// 0x20
|
|
(op) => {
|
|
byte relativeJump = ReadInstruction();
|
|
if (!registers.Flags.Zero)
|
|
{
|
|
registers.PC += relativeJump;
|
|
return 12;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
},
|
|
// 0x21
|
|
(op) => {
|
|
// LD HL, d16
|
|
registers.HL = ReadShortFromInstruction();
|
|
return 12;
|
|
},
|
|
// 0x22
|
|
(op) => {
|
|
// LD (HL+), A
|
|
memory.WriteByte(registers.HL++, registers.A);
|
|
return 8;
|
|
},
|
|
// 0x23
|
|
(op) => {
|
|
registers.HL += 1;
|
|
return 8;
|
|
},
|
|
// 0x24
|
|
(op) => {
|
|
registers.H = IncrementRegister(registers.H);
|
|
|
|
return 4;
|
|
},
|
|
// 0x25
|
|
(op) => {
|
|
registers.H = DecrementRegister(registers.H);
|
|
|
|
return 4;
|
|
},
|
|
// 0x26
|
|
(op) => {
|
|
registers.H = ReadInstruction();
|
|
return 8;
|
|
},
|
|
// 0x27
|
|
(op) => {
|
|
throw new NotImplementedException("0x27");
|
|
},
|
|
// 0x28
|
|
(op) => {
|
|
byte relativeJump = ReadInstruction();
|
|
if (registers.Flags.Zero)
|
|
{
|
|
registers.PC += relativeJump;
|
|
return 12;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
},
|
|
// 0x29
|
|
(op) => {
|
|
registers.HL = AddWideRegisters(registers.HL, registers.HL);
|
|
|
|
return 8;
|
|
},
|
|
// 0x2A
|
|
(op) => {
|
|
byte val = memory.ReadByte(registers.HL++);
|
|
registers.A = val;
|
|
return 8;
|
|
},
|
|
// 0x2B
|
|
(op) => {
|
|
registers.HL -= 1;
|
|
return 8;
|
|
},
|
|
// 0x2C
|
|
(op) => {
|
|
registers.L = IncrementRegister(registers.L);
|
|
|
|
return 4;
|
|
},
|
|
// 0x2D
|
|
(op) => {
|
|
registers.L = DecrementRegister(registers.L);
|
|
|
|
return 4;
|
|
},
|
|
// 0x2E
|
|
(op) => {
|
|
registers.L = ReadInstruction();
|
|
return 8;
|
|
},
|
|
// 0x2F
|
|
(op) => {
|
|
registers.A = (byte)~registers.A;
|
|
registers.Flags.HalfCarry = true;
|
|
registers.Flags.N_Subtract = true;
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x30-0x3F
|
|
// 0x30
|
|
(op) => {
|
|
byte relativeJump = ReadInstruction();
|
|
if (!registers.Flags.Carry)
|
|
{
|
|
registers.PC += relativeJump;
|
|
return 12;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
},
|
|
// 0x31
|
|
(op) => {
|
|
// LD SP, d16
|
|
registers.SP = ReadShortFromInstruction();
|
|
return 12;
|
|
},
|
|
// 0x32
|
|
(op) => {
|
|
memory.WriteByte(registers.HL--, registers.A);
|
|
return 8;
|
|
},
|
|
// 0x33
|
|
(op) => {
|
|
registers.SP += 1;
|
|
return 8;
|
|
},
|
|
// 0x34
|
|
(op) => {
|
|
byte val = IncrementRegister(memory.ReadByte(registers.HL));
|
|
memory.WriteByte(registers.HL, val);
|
|
return 12;
|
|
},
|
|
// 0x35
|
|
(op) => {
|
|
byte val = DecrementRegister(memory.ReadByte(registers.HL));
|
|
memory.WriteByte(registers.HL, val);
|
|
return 12;
|
|
},
|
|
// 0x36
|
|
(op) => {
|
|
byte val = ReadInstruction();
|
|
memory.WriteByte(registers.HL, val);
|
|
return 12;
|
|
},
|
|
// 0x37
|
|
(op) => {
|
|
registers.Flags.Carry = true;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.N_Subtract = false;
|
|
return 4;
|
|
},
|
|
// 0x38
|
|
(op) => {
|
|
byte relativeJump = ReadInstruction();
|
|
if (registers.Flags.Carry)
|
|
{
|
|
registers.PC += relativeJump;
|
|
return 12;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
},
|
|
// 0x39
|
|
(op) => {
|
|
registers.HL = AddWideRegisters(registers.HL, registers.SP);
|
|
|
|
return 8;
|
|
},
|
|
// 0x3A
|
|
(op) => {
|
|
registers.A = memory.ReadByte(registers.HL--);
|
|
return 8;
|
|
},
|
|
// 0x3B
|
|
(op) => {
|
|
registers.SP -= 1;
|
|
|
|
return 8;
|
|
},
|
|
// 0x3C
|
|
(op) => {
|
|
registers.A = IncrementRegister(registers.A);
|
|
|
|
return 4;
|
|
},
|
|
// 0x3D
|
|
(op) => {
|
|
registers.A = DecrementRegister(registers.A);
|
|
|
|
return 4;
|
|
},
|
|
// 0x3E
|
|
(op) => {
|
|
registers.A = ReadInstruction();
|
|
return 8;
|
|
},
|
|
// 0x3F
|
|
(op) => {
|
|
registers.Flags.Carry = !registers.Flags.Carry;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.N_Subtract = false;
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x40-0x4F
|
|
// 0x40
|
|
(op) => {
|
|
registers.B = registers.B;
|
|
return 4;
|
|
},
|
|
// 0x41
|
|
(op) => {
|
|
registers.B = registers.C;
|
|
return 4;
|
|
},
|
|
// 0x42
|
|
(op) => {
|
|
registers.B = registers.D;
|
|
return 4;
|
|
},
|
|
// 0x43
|
|
(op) => {
|
|
registers.B = registers.E;
|
|
return 4;
|
|
},
|
|
// 0x44
|
|
(op) => {
|
|
registers.B = registers.H;
|
|
return 4;
|
|
},
|
|
// 0x45
|
|
(op) => {
|
|
registers.B = registers.L;
|
|
return 4;
|
|
},
|
|
// 0x46
|
|
(op) => {
|
|
registers.B = memory.ReadByte(registers.HL);
|
|
return 8;
|
|
},
|
|
// 0x47
|
|
(op) => {
|
|
registers.B = registers.A;
|
|
return 4;
|
|
},
|
|
// 0x48
|
|
(op) => {
|
|
registers.C = registers.B;
|
|
return 4;
|
|
},
|
|
// 0x49
|
|
(op) => {
|
|
registers.C = registers.C;
|
|
return 4;
|
|
},
|
|
// 0x4A
|
|
(op) => {
|
|
registers.C = registers.D;
|
|
return 4;
|
|
},
|
|
// 0x4B
|
|
(op) => {
|
|
registers.C = registers.E;
|
|
return 4;
|
|
},
|
|
// 0x4C
|
|
(op) => {
|
|
registers.C = registers.H;
|
|
return 4;
|
|
},
|
|
// 0x4D
|
|
(op) => {
|
|
registers.C = registers.L;
|
|
return 4;
|
|
},
|
|
// 0x4E
|
|
(op) => {
|
|
registers.C = memory.ReadByte(registers.HL);
|
|
return 8;
|
|
},
|
|
// 0x4F
|
|
(op) => {
|
|
registers.C = registers.A;
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x50-0x5F
|
|
// 0x50
|
|
(op) => {
|
|
registers.D = registers.B;
|
|
return 4;
|
|
},
|
|
// 0x51
|
|
(op) => {
|
|
registers.D = registers.C;
|
|
return 4;
|
|
},
|
|
// 0x52
|
|
(op) => {
|
|
registers.D = registers.D;
|
|
return 4;
|
|
},
|
|
// 0x53
|
|
(op) => {
|
|
registers.D = registers.E;
|
|
return 4;
|
|
},
|
|
// 0x54
|
|
(op) => {
|
|
registers.D = registers.H;
|
|
return 4;
|
|
},
|
|
// 0x55
|
|
(op) => {
|
|
registers.D = registers.L;
|
|
return 4;
|
|
},
|
|
// 0x56
|
|
(op) => {
|
|
registers.D = memory.ReadByte(registers.HL);
|
|
return 8;
|
|
},
|
|
// 0x57
|
|
(op) => {
|
|
registers.D = registers.A;
|
|
return 4;
|
|
},
|
|
// 0x58
|
|
(op) => {
|
|
registers.E = registers.B;
|
|
return 4;
|
|
},
|
|
// 0x59
|
|
(op) => {
|
|
registers.E = registers.C;
|
|
return 4;
|
|
},
|
|
// 0x5A
|
|
(op) => {
|
|
registers.E = registers.D;
|
|
return 4;
|
|
},
|
|
// 0x5B
|
|
(op) => {
|
|
registers.E = registers.E;
|
|
return 4;
|
|
},
|
|
// 0x5C
|
|
(op) => {
|
|
registers.E = registers.H;
|
|
return 4;
|
|
},
|
|
// 0x5D
|
|
(op) => {
|
|
registers.E = registers.L;
|
|
return 4;
|
|
},
|
|
// 0x5E
|
|
(op) => {
|
|
registers.E = memory.ReadByte(registers.HL);
|
|
return 8;
|
|
},
|
|
// 0x5F
|
|
(op) => {
|
|
registers.E = registers.A;
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x60-0x6F
|
|
// 0x60
|
|
(op) => {
|
|
registers.H = registers.B;
|
|
return 4;
|
|
},
|
|
// 0x61
|
|
(op) => {
|
|
registers.H = registers.C;
|
|
return 4;
|
|
},
|
|
// 0x62
|
|
(op) => {
|
|
registers.H = registers.D;
|
|
return 4;
|
|
},
|
|
// 0x63
|
|
(op) => {
|
|
registers.H = registers.E;
|
|
return 4;
|
|
},
|
|
// 0x64
|
|
(op) => {
|
|
registers.H = registers.H;
|
|
return 4;
|
|
},
|
|
// 0x65
|
|
(op) => {
|
|
registers.H = registers.L;
|
|
return 4;
|
|
},
|
|
// 0x66
|
|
(op) => {
|
|
registers.H = memory.ReadByte(registers.HL);
|
|
return 8;
|
|
},
|
|
// 0x67
|
|
(op) => {
|
|
registers.H = registers.A;
|
|
return 4;
|
|
},
|
|
// 0x68
|
|
(op) => {
|
|
registers.L = registers.B;
|
|
return 4;
|
|
},
|
|
// 0x69
|
|
(op) => {
|
|
registers.L = registers.C;
|
|
return 4;
|
|
},
|
|
// 0x6A
|
|
(op) => {
|
|
registers.L = registers.D;
|
|
return 4;
|
|
},
|
|
// 0x6B
|
|
(op) => {
|
|
registers.L = registers.E;
|
|
return 4;
|
|
},
|
|
// 0x6C
|
|
(op) => {
|
|
registers.L = registers.H;
|
|
return 4;
|
|
},
|
|
// 0x6D
|
|
(op) => {
|
|
registers.L = registers.L;
|
|
return 4;
|
|
},
|
|
// 0x6E
|
|
(op) => {
|
|
registers.L = memory.ReadByte(registers.HL);
|
|
return 8;
|
|
},
|
|
// 0x6F
|
|
(op) => {
|
|
registers.L = registers.A;
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x70-0x7F
|
|
// 0x70
|
|
(op) => {
|
|
memory.WriteByte(registers.HL, registers.B);
|
|
return 8;
|
|
},
|
|
// 0x71
|
|
(op) => {
|
|
memory.WriteByte(registers.HL, registers.C);
|
|
return 8;
|
|
},
|
|
// 0x72
|
|
(op) => {
|
|
memory.WriteByte(registers.HL, registers.D);
|
|
return 8;
|
|
},
|
|
// 0x73
|
|
(op) => {
|
|
memory.WriteByte(registers.HL, registers.E);
|
|
return 8;
|
|
},
|
|
// 0x74
|
|
(op) => {
|
|
memory.WriteByte(registers.HL, registers.H);
|
|
return 8;
|
|
},
|
|
// 0x75
|
|
(op) => {
|
|
memory.WriteByte(registers.HL, registers.L);
|
|
return 8;
|
|
},
|
|
// 0x76
|
|
(op) => {
|
|
halted = true;
|
|
return 4;
|
|
},
|
|
// 0x77
|
|
(op) => {
|
|
memory.WriteByte(registers.HL, registers.A);
|
|
return 8;
|
|
},
|
|
// 0x78
|
|
(op) => {
|
|
registers.A = registers.B;
|
|
return 4;
|
|
},
|
|
// 0x79
|
|
(op) => {
|
|
registers.A = registers.C;
|
|
return 4;
|
|
},
|
|
// 0x7A
|
|
(op) => {
|
|
registers.A = registers.D;
|
|
return 4;
|
|
},
|
|
// 0x7B
|
|
(op) => {
|
|
registers.A = registers.E;
|
|
return 4;
|
|
},
|
|
// 0x7C
|
|
(op) => {
|
|
registers.A = registers.H;
|
|
return 4;
|
|
},
|
|
// 0x7D
|
|
(op) => {
|
|
registers.A = registers.L;
|
|
return 4;
|
|
},
|
|
// 0x7E
|
|
(op) => {
|
|
registers.A = memory.ReadByte(registers.HL);
|
|
return 8;
|
|
},
|
|
// 0x7F
|
|
(op) => {
|
|
registers.A = registers.A;
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x80-0x8F
|
|
// 0x80
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.B);
|
|
return 4;
|
|
},
|
|
// 0x81
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.C);
|
|
return 4;
|
|
},
|
|
// 0x82
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.D);
|
|
return 4;
|
|
},
|
|
// 0x83
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.E);
|
|
return 4;
|
|
},
|
|
// 0x84
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.H);
|
|
return 4;
|
|
},
|
|
// 0x85
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.L);
|
|
return 4;
|
|
},
|
|
// 0x86
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, memory.ReadByte(registers.HL));
|
|
return 8;
|
|
},
|
|
// 0x87
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.A);
|
|
return 4;
|
|
},
|
|
// 0x88
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.B, true);
|
|
return 4;
|
|
},
|
|
// 0x89
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.C, true);
|
|
return 4;
|
|
},
|
|
// 0x8A
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.D, true);
|
|
return 4;
|
|
},
|
|
// 0x8B
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.E, true);
|
|
return 4;
|
|
},
|
|
// 0x8C
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.H, true);
|
|
return 4;
|
|
},
|
|
// 0x8D
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.L, true);
|
|
return 4;
|
|
},
|
|
// 0x8E
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, memory.ReadByte(registers.HL), true);
|
|
return 8;
|
|
},
|
|
// 0x8F
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, registers.A, true);
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0x90-0x9F
|
|
// 0x90
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.B);
|
|
return 4;
|
|
},
|
|
// 0x91
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.C);
|
|
return 4;
|
|
},
|
|
// 0x92
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.D);
|
|
return 4;
|
|
},
|
|
// 0x93
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.E);
|
|
return 4;
|
|
},
|
|
// 0x94
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.H);
|
|
return 4;
|
|
},
|
|
// 0x95
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.L);
|
|
return 4;
|
|
},
|
|
// 0x96
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, memory.ReadByte(registers.HL));
|
|
return 8;
|
|
},
|
|
// 0x97
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.A);
|
|
return 4;
|
|
},
|
|
// 0x98
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.B, true);
|
|
return 4;
|
|
},
|
|
// 0x99
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.C, true);
|
|
return 4;
|
|
},
|
|
// 0x9A
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.D, true);
|
|
return 4;
|
|
},
|
|
// 0x9B
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.E, true);
|
|
return 4;
|
|
},
|
|
// 0x9C
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.H, true);
|
|
return 4;
|
|
},
|
|
// 0x9D
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.L, true);
|
|
return 4;
|
|
},
|
|
// 0x9E
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, memory.ReadByte(registers.HL), true);
|
|
return 8;
|
|
},
|
|
// 0x9F
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, registers.A, true);
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xA0-0xAF
|
|
// 0xA0
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, registers.B);
|
|
return 4;
|
|
},
|
|
// 0xA1
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, registers.C);
|
|
return 4;
|
|
},
|
|
// 0xA2
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, registers.D);
|
|
return 4;
|
|
},
|
|
// 0xA3
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, registers.E);
|
|
return 4;
|
|
},
|
|
// 0xA4
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, registers.H);
|
|
return 4;
|
|
},
|
|
// 0xA5
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, registers.L);
|
|
return 4;
|
|
},
|
|
// 0xA6
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, memory.ReadByte(registers.HL));
|
|
return 8;
|
|
},
|
|
// 0xA7
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, registers.A);
|
|
return 4;
|
|
},
|
|
// 0xA8
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, registers.B);
|
|
return 4;
|
|
},
|
|
// 0xA9
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, registers.C);
|
|
return 4;
|
|
},
|
|
// 0xAA
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, registers.D);
|
|
return 4;
|
|
},
|
|
// 0xAB
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, registers.E);
|
|
return 4;
|
|
},
|
|
// 0xAC
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, registers.H);
|
|
return 4;
|
|
},
|
|
// 0xAD
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, registers.L);
|
|
return 4;
|
|
},
|
|
// 0xAE
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, memory.ReadByte(registers.HL));
|
|
return 8;
|
|
},
|
|
// 0xAF
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, registers.A);
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xB0-0xBF
|
|
// 0xB0
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, registers.B);
|
|
return 4;
|
|
},
|
|
// 0xB1
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, registers.C);
|
|
return 4;
|
|
},
|
|
// 0xB2
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, registers.D);
|
|
return 4;
|
|
},
|
|
// 0xB3
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, registers.E);
|
|
return 4;
|
|
},
|
|
// 0xB4
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, registers.H);
|
|
return 4;
|
|
},
|
|
// 0xB5
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, registers.L);
|
|
return 4;
|
|
},
|
|
// 0xB6
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, memory.ReadByte(registers.HL));
|
|
return 8;
|
|
},
|
|
// 0xB7
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, registers.A);
|
|
return 4;
|
|
},
|
|
// 0xB8
|
|
(op) => {
|
|
SubtractRegisters(registers.A, registers.B);
|
|
return 4;
|
|
},
|
|
// 0xB9
|
|
(op) => {
|
|
SubtractRegisters(registers.A, registers.C);
|
|
return 4;
|
|
},
|
|
// 0xBA
|
|
(op) => {
|
|
SubtractRegisters(registers.A, registers.D);
|
|
return 4;
|
|
},
|
|
// 0xBB
|
|
(op) => {
|
|
SubtractRegisters(registers.A, registers.E);
|
|
return 4;
|
|
},
|
|
// 0xBC
|
|
(op) => {
|
|
SubtractRegisters(registers.A, registers.H);
|
|
return 4;
|
|
},
|
|
// 0xBD
|
|
(op) => {
|
|
SubtractRegisters(registers.A, registers.L);
|
|
return 4;
|
|
},
|
|
// 0xBE
|
|
(op) => {
|
|
SubtractRegisters(registers.A, memory.ReadByte(registers.HL));
|
|
return 8;
|
|
},
|
|
// 0xBF
|
|
(op) => {
|
|
SubtractRegisters(registers.A, registers.A);
|
|
return 4;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xC0-0xCF
|
|
// 0xC0
|
|
(op) => {
|
|
if (!registers.Flags.Zero)
|
|
{
|
|
Jump(PopShort());
|
|
return 20;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
},
|
|
// 0xC1
|
|
(op) => {
|
|
registers.BC = PopShort();
|
|
return 12;
|
|
},
|
|
// 0xC2
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
if (!registers.Flags.Zero)
|
|
{
|
|
Jump(jumpAddress);
|
|
return 16;
|
|
}
|
|
else
|
|
{
|
|
return 12;
|
|
}
|
|
},
|
|
// 0xC3
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
Jump(jumpAddress);
|
|
return 16;
|
|
},
|
|
// 0xC4
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
if (!registers.Flags.Zero)
|
|
{
|
|
PushShort(registers.PC);
|
|
Jump(jumpAddress);
|
|
return 16;
|
|
}
|
|
else
|
|
{
|
|
return 12;
|
|
}
|
|
},
|
|
// 0xC5
|
|
(op) => {
|
|
PushShort(registers.BC);
|
|
return 16;
|
|
},
|
|
// 0xC6
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, ReadInstruction());
|
|
return 8;
|
|
},
|
|
// 0xC7
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(0x0000);
|
|
return 16;
|
|
},
|
|
// 0xC8
|
|
(op) => {
|
|
if (registers.Flags.Zero)
|
|
{
|
|
Jump(PopShort());
|
|
return 20;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
},
|
|
// 0xC9
|
|
(op) => {
|
|
Jump(PopShort());
|
|
return 16;
|
|
},
|
|
// 0xCA
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
if (registers.Flags.Zero)
|
|
{
|
|
Jump(jumpAddress);
|
|
return 16;
|
|
}
|
|
else
|
|
{
|
|
return 12;
|
|
}
|
|
},
|
|
// 0xCB
|
|
(op) => {
|
|
throw new NotImplementedException("0xCB");
|
|
},
|
|
// 0xCC
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
if (registers.Flags.Zero)
|
|
{
|
|
PushShort(registers.PC);
|
|
Jump(jumpAddress);
|
|
return 24;
|
|
}
|
|
else
|
|
{
|
|
return 12;
|
|
}
|
|
},
|
|
// 0xCD
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(ReadShortFromInstruction());
|
|
return 24;
|
|
},
|
|
// 0xCE
|
|
(op) => {
|
|
registers.A = AddRegisters(registers.A, ReadInstruction(), true);
|
|
return 8;
|
|
},
|
|
// 0xCF
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(0x0008);
|
|
return 16;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xD0-0xDF
|
|
// 0xD0
|
|
(op) => {
|
|
if (!registers.Flags.Carry)
|
|
{
|
|
Jump(PopShort());
|
|
return 20;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
},
|
|
// 0xD1
|
|
(op) => {
|
|
registers.DE = PopShort();
|
|
return 12;
|
|
},
|
|
// 0xD2
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
if (!registers.Flags.Carry)
|
|
{
|
|
Jump(jumpAddress);
|
|
return 16;
|
|
}
|
|
else
|
|
{
|
|
return 12;
|
|
}
|
|
},
|
|
// 0xD3
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist: 0xD3");
|
|
},
|
|
// 0xD4
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
if (!registers.Flags.Carry)
|
|
{
|
|
PushShort(registers.PC);
|
|
Jump(jumpAddress);
|
|
return 24;
|
|
}
|
|
else
|
|
{
|
|
return 12;
|
|
}
|
|
},
|
|
// 0xD5
|
|
(op) => {
|
|
PushShort(registers.DE);
|
|
return 16;
|
|
},
|
|
// 0xD6
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, ReadInstruction());
|
|
return 8;
|
|
},
|
|
// 0xD7
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(0x0010);
|
|
return 16;
|
|
},
|
|
// 0xD8
|
|
(op) => {
|
|
if (registers.Flags.Carry)
|
|
{
|
|
Jump(PopShort());
|
|
return 20;
|
|
}
|
|
else
|
|
{
|
|
return 8;
|
|
}
|
|
},
|
|
// 0xD9
|
|
(op) => {
|
|
Jump(PopShort());
|
|
interruptsEnabled = true;
|
|
return 16;
|
|
},
|
|
// 0xDA
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
if (registers.Flags.Carry)
|
|
{
|
|
Jump(jumpAddress);
|
|
return 16;
|
|
}
|
|
else
|
|
{
|
|
return 12;
|
|
}
|
|
},
|
|
// 0xDB
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xDC
|
|
(op) => {
|
|
ushort jumpAddress = ReadShortFromInstruction();
|
|
if (registers.Flags.Carry)
|
|
{
|
|
PushShort(registers.PC);
|
|
Jump(jumpAddress);
|
|
return 24;
|
|
}
|
|
else
|
|
{
|
|
return 12;
|
|
}
|
|
},
|
|
// 0xDD
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xDE
|
|
(op) => {
|
|
registers.A = SubtractRegisters(registers.A, ReadInstruction(), true);
|
|
return 8;
|
|
},
|
|
// 0xDF
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(0x0018);
|
|
return 16;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xE0-0xEF
|
|
// 0xE0
|
|
(op) => {
|
|
memory.WriteByte(0xFF00 + ReadInstruction(), registers.A);
|
|
return 12;
|
|
},
|
|
// 0xE1
|
|
(op) => {
|
|
registers.HL = PopShort();
|
|
return 12;
|
|
},
|
|
// 0xE2
|
|
(op) => {
|
|
memory.WriteByte(0xFF00 + registers.C, registers.A);
|
|
return 8;
|
|
},
|
|
// 0xE3
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xE4
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xE5
|
|
(op) => {
|
|
PushShort(registers.HL);
|
|
return 16;
|
|
},
|
|
// 0xE6
|
|
(op) => {
|
|
registers.A = AndRegisters(registers.A, ReadInstruction());
|
|
return 8;
|
|
},
|
|
// 0xE7
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(0x0020);
|
|
return 16;
|
|
},
|
|
// 0xE8
|
|
(op) => {
|
|
registers.SP = AddWideRegisters(registers.SP, ReadInstruction());
|
|
registers.Flags.Zero = false;
|
|
return 16;
|
|
},
|
|
// 0xE9
|
|
(op) => {
|
|
Jump(registers.HL);
|
|
return 4;
|
|
},
|
|
// 0xEA
|
|
(op) => {
|
|
memory.WriteByte(ReadShortFromInstruction(), registers.A);
|
|
return 16;
|
|
},
|
|
// 0xEB
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xEC
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xED
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xEE
|
|
(op) => {
|
|
registers.A = XorRegisters(registers.A, ReadInstruction());
|
|
return 8;
|
|
},
|
|
// 0xEF
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(0x0028);
|
|
return 16;
|
|
},
|
|
#endregion
|
|
#region OpCodes 0xF0-0xFF
|
|
// 0xF0
|
|
(op) => {
|
|
registers.A = memory.ReadByte(0xFF + ReadInstruction());
|
|
return 12;
|
|
},
|
|
// 0xF1
|
|
(op) => {
|
|
registers.AF = PopShort();
|
|
return 12;
|
|
},
|
|
// 0xF2
|
|
(op) => {
|
|
registers.A = memory.ReadByte(0xFF + registers.C);
|
|
return 8;
|
|
throw new NotImplementedException("0xF2");
|
|
},
|
|
// 0xF3
|
|
(op) => {
|
|
interruptsEnabled = false;
|
|
return 4;
|
|
},
|
|
// 0xF4
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist: 0xF4");
|
|
},
|
|
// 0xF5
|
|
(op) => {
|
|
PushShort(registers.AF);
|
|
return 16;
|
|
},
|
|
// 0xF6
|
|
(op) => {
|
|
registers.A = OrRegisters(registers.A, ReadInstruction());
|
|
throw new NotImplementedException("0xF6");
|
|
},
|
|
// 0xF7
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(0x0030);
|
|
return 16;
|
|
},
|
|
// 0xF8
|
|
(op) => {
|
|
registers.HL = AddWideRegisters(registers.SP, ReadInstruction());
|
|
registers.Flags.Zero = false;
|
|
return 12;
|
|
},
|
|
// 0xF9
|
|
(op) => {
|
|
registers.SP = registers.HL;
|
|
return 4;
|
|
},
|
|
// 0xFA
|
|
(op) => {
|
|
registers.A = memory.ReadByte(ReadShortFromInstruction());
|
|
return 16;
|
|
},
|
|
// 0xFB
|
|
(op) => {
|
|
interruptsEnabled = true;
|
|
return 4;
|
|
},
|
|
// 0xFC
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xFD
|
|
(op) => {
|
|
throw new IllegalInstructionException(op, "Instruction does not exist");
|
|
},
|
|
// 0xFE
|
|
(op) => {
|
|
SubtractRegisters(registers.A, ReadInstruction());
|
|
return 8;
|
|
},
|
|
// 0xFF
|
|
(op) => {
|
|
PushShort(registers.PC);
|
|
Jump(0x0038);
|
|
return 16;
|
|
}
|
|
#endregion
|
|
#endregion
|
|
};
|
|
}
|
|
|
|
private void Jump(ushort address)
|
|
{
|
|
registers.PC = address;
|
|
}
|
|
|
|
private void Jump(byte msb, byte lsb)
|
|
{
|
|
Jump(BytesToShort(msb, lsb));
|
|
}
|
|
|
|
private void PushShort(ushort value)
|
|
{
|
|
memory.WriteByte(--registers.SP, (byte)(value >> 8));
|
|
memory.WriteByte(--registers.SP, (byte)(value & 0xFF));
|
|
}
|
|
|
|
private ushort PopShort()
|
|
{
|
|
byte lsb = memory.ReadByte(registers.SP++);
|
|
byte msb = memory.ReadByte(registers.SP++);
|
|
return BytesToShort(msb, lsb);
|
|
}
|
|
|
|
private byte ReadInstruction()
|
|
{
|
|
registers.PC += 1;
|
|
return 0;
|
|
}
|
|
|
|
private ushort ReadShortFromInstruction()
|
|
{
|
|
byte lsb = ReadInstruction();
|
|
byte msb = ReadInstruction();
|
|
return BytesToShort(msb, lsb);
|
|
}
|
|
|
|
private ushort BytesToShort(byte msb, byte lsb)
|
|
{
|
|
return (ushort)(lsb + (msb << 8));
|
|
}
|
|
|
|
private byte IncrementRegister(byte register)
|
|
{
|
|
return AddRegisters(register, 1);
|
|
}
|
|
|
|
private byte DecrementRegister(byte register)
|
|
{
|
|
return SubtractRegisters(register, 1);
|
|
}
|
|
|
|
private byte AddRegisters(byte register1, byte register2, bool withCarry = false)
|
|
{
|
|
if (withCarry && registers.Flags.Carry)
|
|
{
|
|
register2 += 1;
|
|
}
|
|
byte reg = (byte)(register1 + register2);
|
|
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.Zero = reg == 0;
|
|
registers.Flags.Carry = ((register1 + register2) & 0x100) == 0x100;
|
|
registers.Flags.HalfCarry = (((register1 & 0xf) + (register2 & 0xf)) & 0x10) == 0x10;
|
|
|
|
return reg;
|
|
}
|
|
|
|
private byte SubtractRegisters(byte register1, byte register2, bool withCarry = false)
|
|
{
|
|
if (withCarry && registers.Flags.Carry)
|
|
{
|
|
register2 += 1;
|
|
}
|
|
byte reg = (byte)(register1 - register2);
|
|
|
|
registers.Flags.N_Subtract = true;
|
|
registers.Flags.Zero = reg == 0;
|
|
registers.Flags.Carry = ((0x100 + register1 + register2) & 0x100) == 0x100;
|
|
registers.Flags.HalfCarry = ((0x10 + (register1 & 0xf) - (register2 & 0xf)) & 0x10) == 0x10;
|
|
|
|
return reg;
|
|
}
|
|
|
|
private byte AndRegisters(byte register1, byte register2)
|
|
{
|
|
byte val = (byte)(register1 & register2);
|
|
|
|
registers.Flags.Carry = false;
|
|
registers.Flags.HalfCarry = true;
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.Zero = val == 0;
|
|
|
|
return val;
|
|
}
|
|
|
|
private byte OrRegisters(byte register1, byte register2)
|
|
{
|
|
byte val = (byte)(register1 | register2);
|
|
|
|
registers.Flags.Carry = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.Zero = val == 0;
|
|
|
|
return val;
|
|
}
|
|
|
|
private byte XorRegisters(byte register1, byte register2)
|
|
{
|
|
byte val = (byte)(register1 ^ register2);
|
|
|
|
registers.Flags.Carry = false;
|
|
registers.Flags.HalfCarry = false;
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.Zero = val == 0;
|
|
|
|
return val;
|
|
}
|
|
|
|
private ushort AddWideRegisters(ushort wideRegister1, ushort wideRegister2)
|
|
{
|
|
// ADD HL, BC
|
|
registers.Flags.N_Subtract = false;
|
|
registers.Flags.HalfCarry = (((wideRegister1 & 0x0FFF) + (wideRegister2 & 0x0FFF) & 0x1000) == 0x1000);
|
|
registers.Flags.Carry = (((wideRegister1 + wideRegister2) & 0x10000) == 0x10000);
|
|
|
|
return (ushort)(wideRegister1 + wideRegister2);
|
|
}
|
|
}
|
|
|
|
|
|
[Serializable]
|
|
public class IllegalInstructionException : Exception
|
|
{
|
|
public OpCode OpCode { get; set; }
|
|
public IllegalInstructionException() { }
|
|
public IllegalInstructionException(OpCode opCode, string message) : base(message)
|
|
{
|
|
OpCode = opCode;
|
|
}
|
|
public IllegalInstructionException(string message) : base(message) { }
|
|
public IllegalInstructionException(string message, Exception inner) : base(message, inner) { }
|
|
protected IllegalInstructionException(
|
|
System.Runtime.Serialization.SerializationInfo info,
|
|
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
|
}
|
|
}
|