Implemented a load more Z80 OpCodes. Added IX, IY and Interrupts to Debugger
This commit is contained in:
113
Core/Cpu/Z80.cs
113
Core/Cpu/Z80.cs
@@ -11,8 +11,8 @@ namespace Core.Cpu
|
||||
public int InterruptMode { get; private set; } = 0; // Defaults to 0 on power-up
|
||||
|
||||
// Interrupt Flip-Flops
|
||||
public bool IFF1;
|
||||
public bool IFF2;
|
||||
public bool IFF1 { get; private set; } = false;
|
||||
public bool IFF2 { get; private set; } = false;
|
||||
|
||||
// Main Register Set
|
||||
public RegisterPair AF;
|
||||
@@ -298,6 +298,17 @@ namespace Core.Cpu
|
||||
return (bits % 2) == 0;
|
||||
}
|
||||
|
||||
private void Push(ushort value)
|
||||
{
|
||||
// High byte goes first
|
||||
SP--;
|
||||
_memory.Write(SP, (byte)(value >> 8));
|
||||
|
||||
// Low byte goes second
|
||||
SP--;
|
||||
_memory.Write(SP, (byte)(value & 0xFF));
|
||||
}
|
||||
|
||||
private int ExecuteOpcode(byte opcode)
|
||||
{
|
||||
sbyte offset = 0;
|
||||
@@ -311,6 +322,18 @@ namespace Core.Cpu
|
||||
case 0x04: // INC B
|
||||
BC.High = Inc8(BC.High);
|
||||
return 4;
|
||||
case 0x10: // DJNZ d
|
||||
sbyte djnzOffset = (sbyte)FetchByte();
|
||||
|
||||
BC.High--; // Decrement the B register
|
||||
|
||||
if (BC.High != 0)
|
||||
{
|
||||
PC = (ushort)(PC + djnzOffset);
|
||||
return 13; // Jump taken
|
||||
}
|
||||
|
||||
return 8; // Loop finished, no jump
|
||||
case 0x11: //LD DE, nn
|
||||
DE.Word = FetchWord();
|
||||
return 10;
|
||||
@@ -366,6 +389,12 @@ namespace Core.Cpu
|
||||
return 12; // Jump taken
|
||||
}
|
||||
return 7; // Jump not taken
|
||||
case 0x32: // LD (nn), A
|
||||
{
|
||||
ushort destAddress = FetchWord();
|
||||
_memory.Write(destAddress, AF.High);
|
||||
return 13;
|
||||
}
|
||||
case 0x35: // DEC (HL)
|
||||
// Read the current byte from memory
|
||||
byte memValue = _memory.Read(HL.Word);
|
||||
@@ -394,6 +423,9 @@ namespace Core.Cpu
|
||||
case 0x6B: // LD L, E
|
||||
HL.Low = DE.Low;
|
||||
return 4;
|
||||
case 0x77: // LD (HL), A
|
||||
_memory.Write(HL.Word, AF.High);
|
||||
return 7;
|
||||
case 0xA7: // AND A
|
||||
And(AF.High);
|
||||
return 4;
|
||||
@@ -407,6 +439,11 @@ namespace Core.Cpu
|
||||
case 0xC3:
|
||||
PC = FetchWord();
|
||||
return 10;
|
||||
case 0xCD: // CALL nn
|
||||
ushort callAddress = FetchWord();
|
||||
Push(PC);
|
||||
PC = callAddress;
|
||||
return 17;
|
||||
case 0xD3: // OUT (n), A
|
||||
byte portOffset = FetchByte();
|
||||
|
||||
@@ -447,6 +484,10 @@ namespace Core.Cpu
|
||||
case 0xF9: // LD SP, HL
|
||||
SP = HL.Word; // (Use SP.Word = HL.Word if you made SP a RegisterPair)
|
||||
return 6;
|
||||
case 0xFB: // EI
|
||||
IFF1 = true;
|
||||
IFF2 = true;
|
||||
return 4;
|
||||
case 0xFD:
|
||||
return ExecuteFDPrefix();
|
||||
default:
|
||||
@@ -457,6 +498,7 @@ namespace Core.Cpu
|
||||
{
|
||||
// Fetch the actual extended instruction
|
||||
byte extendedOpcode = _memory.Read(PC++);
|
||||
byte val = 0;
|
||||
|
||||
switch (extendedOpcode)
|
||||
{
|
||||
@@ -478,10 +520,37 @@ namespace Core.Cpu
|
||||
return 20;
|
||||
case 0x56: // IM 1
|
||||
InterruptMode = 1;
|
||||
return 8; // Takes 8 T-States
|
||||
return 8;
|
||||
case 0xB0: // LDIR
|
||||
// 1. Read byte from (HL)
|
||||
val = _memory.Read(HL.Word);
|
||||
|
||||
// 2. Write byte to (DE)
|
||||
_memory.Write(DE.Word, val);
|
||||
|
||||
// 3. Increment memory pointers, Decrement byte counter
|
||||
HL.Word++;
|
||||
DE.Word++;
|
||||
BC.Word--;
|
||||
|
||||
// 4. Update Flags
|
||||
// Preserve S (0x80), Z (0x40), and C (0x01).
|
||||
// H (0x10) and N (0x02) are always reset to 0.
|
||||
AF.Low &= 0xC1;
|
||||
|
||||
// P/V Flag (Bit 2) is set to 1 if BC is not 0
|
||||
if (BC.Word != 0)
|
||||
{
|
||||
AF.Low |= 0x04;
|
||||
|
||||
// Rewind the PC so the CPU executes this instruction again!
|
||||
PC -= 2;
|
||||
return 21; // Looping
|
||||
}
|
||||
return 16;
|
||||
case 0xB8: // LDDR
|
||||
// 1. Read byte from (HL)
|
||||
byte val = _memory.Read(HL.Word);
|
||||
val = _memory.Read(HL.Word);
|
||||
|
||||
// 2. Write byte to (DE)
|
||||
_memory.Write(DE.Word, val);
|
||||
@@ -515,13 +584,47 @@ namespace Core.Cpu
|
||||
private int ExecuteFDPrefix()
|
||||
{
|
||||
byte opcode = FetchByte();
|
||||
ushort targetAddress = 0;
|
||||
byte memVal = 0;
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x21: // LD IY, nn
|
||||
IY.Word = FetchWord();
|
||||
return 14; // Takes 14 T-States
|
||||
return 14;
|
||||
case 0x35: // DEC (IY+d)
|
||||
sbyte offset = (sbyte)FetchByte();
|
||||
targetAddress = (ushort)(IY.Word + offset);
|
||||
|
||||
// Read, decrement using your existing helper, and write back
|
||||
memVal = _memory.Read(targetAddress);
|
||||
byte decVal = Dec8(memVal);
|
||||
_memory.Write(targetAddress, decVal);
|
||||
return 23;
|
||||
case 0x75: // LD (IY+d), L
|
||||
sbyte offset75 = (sbyte)FetchByte();
|
||||
targetAddress = (ushort)(IY.Word + offset75);
|
||||
// Write the low byte of HL to memory
|
||||
_memory.Write(targetAddress, HL.Low);
|
||||
return 19;
|
||||
case 0xCB: // The FD CB nested prefix
|
||||
{
|
||||
sbyte offsetCB = (sbyte)FetchByte(); // This is the '01'
|
||||
byte bitOpcode = FetchByte(); // This is the 'CE'
|
||||
targetAddress = (ushort)(IY.Word + offsetCB);
|
||||
|
||||
switch (bitOpcode)
|
||||
{
|
||||
case 0xCE: // SET 1, (IY+d)
|
||||
memVal = _memory.Read(targetAddress);
|
||||
memVal |= 0x02; // 0x02 is Binary 0000 0010 (Bit 1)
|
||||
_memory.Write(targetAddress, memVal);
|
||||
return 23; // Takes 23 T-States
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"FD CB opcode {bitOpcode:X2} not implemented!");
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException($"FD prefix opcode {opcode:X2} not implemented!");
|
||||
}
|
||||
|
||||
131
Desktop/DebuggerForm.Designer.cs
generated
131
Desktop/DebuggerForm.Designer.cs
generated
@@ -50,94 +50,97 @@
|
||||
label2 = new Label();
|
||||
lblIX = new Label();
|
||||
lblIY = new Label();
|
||||
lblIff1 = new Label();
|
||||
lblIff2 = new Label();
|
||||
lblIE = new Label();
|
||||
SuspendLayout();
|
||||
//
|
||||
// lblAF
|
||||
//
|
||||
lblAF.AutoSize = true;
|
||||
lblAF.Location = new Point(12, 9);
|
||||
lblAF.Location = new Point(10, 7);
|
||||
lblAF.Margin = new Padding(2, 0, 2, 0);
|
||||
lblAF.Name = "lblAF";
|
||||
lblAF.Size = new Size(33, 25);
|
||||
lblAF.Size = new Size(26, 20);
|
||||
lblAF.TabIndex = 0;
|
||||
lblAF.Text = "AF";
|
||||
//
|
||||
// lblBC
|
||||
//
|
||||
lblBC.AutoSize = true;
|
||||
lblBC.Location = new Point(11, 60);
|
||||
lblBC.Location = new Point(9, 48);
|
||||
lblBC.Margin = new Padding(2, 0, 2, 0);
|
||||
lblBC.Name = "lblBC";
|
||||
lblBC.Size = new Size(33, 25);
|
||||
lblBC.Size = new Size(27, 20);
|
||||
lblBC.TabIndex = 1;
|
||||
lblBC.Text = "BC";
|
||||
//
|
||||
// lblDE
|
||||
//
|
||||
lblDE.AutoSize = true;
|
||||
lblDE.Location = new Point(12, 125);
|
||||
lblDE.Location = new Point(10, 100);
|
||||
lblDE.Margin = new Padding(2, 0, 2, 0);
|
||||
lblDE.Name = "lblDE";
|
||||
lblDE.Size = new Size(34, 25);
|
||||
lblDE.Size = new Size(28, 20);
|
||||
lblDE.TabIndex = 2;
|
||||
lblDE.Text = "DE";
|
||||
//
|
||||
// lblHL
|
||||
//
|
||||
lblHL.AutoSize = true;
|
||||
lblHL.Location = new Point(12, 188);
|
||||
lblHL.Location = new Point(10, 150);
|
||||
lblHL.Margin = new Padding(2, 0, 2, 0);
|
||||
lblHL.Name = "lblHL";
|
||||
lblHL.Size = new Size(33, 25);
|
||||
lblHL.Size = new Size(27, 20);
|
||||
lblHL.TabIndex = 3;
|
||||
lblHL.Text = "HL";
|
||||
//
|
||||
// lblPC
|
||||
//
|
||||
lblPC.AutoSize = true;
|
||||
lblPC.Location = new Point(11, 250);
|
||||
lblPC.Location = new Point(9, 200);
|
||||
lblPC.Margin = new Padding(2, 0, 2, 0);
|
||||
lblPC.Name = "lblPC";
|
||||
lblPC.Size = new Size(33, 25);
|
||||
lblPC.Size = new Size(26, 20);
|
||||
lblPC.TabIndex = 4;
|
||||
lblPC.Text = "PC";
|
||||
//
|
||||
// lblSP
|
||||
//
|
||||
lblSP.AutoSize = true;
|
||||
lblSP.Location = new Point(11, 315);
|
||||
lblSP.Location = new Point(9, 252);
|
||||
lblSP.Margin = new Padding(2, 0, 2, 0);
|
||||
lblSP.Name = "lblSP";
|
||||
lblSP.Size = new Size(32, 25);
|
||||
lblSP.Size = new Size(25, 20);
|
||||
lblSP.TabIndex = 6;
|
||||
lblSP.Text = "SP";
|
||||
//
|
||||
// lblFlags
|
||||
//
|
||||
lblFlags.AutoSize = true;
|
||||
lblFlags.Location = new Point(110, 65);
|
||||
lblFlags.Location = new Point(88, 52);
|
||||
lblFlags.Margin = new Padding(2, 0, 2, 0);
|
||||
lblFlags.Name = "lblFlags";
|
||||
lblFlags.Size = new Size(53, 25);
|
||||
lblFlags.Size = new Size(43, 20);
|
||||
lblFlags.TabIndex = 7;
|
||||
lblFlags.Text = "Flags";
|
||||
//
|
||||
// lblTStates
|
||||
//
|
||||
lblTStates.AutoSize = true;
|
||||
lblTStates.Location = new Point(110, 9);
|
||||
lblTStates.Location = new Point(88, 7);
|
||||
lblTStates.Margin = new Padding(2, 0, 2, 0);
|
||||
lblTStates.Name = "lblTStates";
|
||||
lblTStates.Size = new Size(75, 25);
|
||||
lblTStates.Size = new Size(63, 20);
|
||||
lblTStates.TabIndex = 8;
|
||||
lblTStates.Text = "T-States";
|
||||
//
|
||||
// txtMemoryStart
|
||||
//
|
||||
txtMemoryStart.Location = new Point(375, 26);
|
||||
txtMemoryStart.Location = new Point(300, 21);
|
||||
txtMemoryStart.Margin = new Padding(2);
|
||||
txtMemoryStart.Name = "txtMemoryStart";
|
||||
txtMemoryStart.Size = new Size(150, 31);
|
||||
txtMemoryStart.Size = new Size(121, 27);
|
||||
txtMemoryStart.TabIndex = 9;
|
||||
txtMemoryStart.Text = "Memory Start";
|
||||
txtMemoryStart.TextAlign = HorizontalAlignment.Center;
|
||||
@@ -145,10 +148,10 @@
|
||||
//
|
||||
// btnStep
|
||||
//
|
||||
btnStep.Location = new Point(8, 523);
|
||||
btnStep.Location = new Point(6, 418);
|
||||
btnStep.Margin = new Padding(2);
|
||||
btnStep.Name = "btnStep";
|
||||
btnStep.Size = new Size(112, 34);
|
||||
btnStep.Size = new Size(90, 27);
|
||||
btnStep.TabIndex = 12;
|
||||
btnStep.Text = "Step";
|
||||
btnStep.UseVisualStyleBackColor = true;
|
||||
@@ -156,10 +159,10 @@
|
||||
//
|
||||
// btnRun
|
||||
//
|
||||
btnRun.Location = new Point(149, 523);
|
||||
btnRun.Location = new Point(119, 418);
|
||||
btnRun.Margin = new Padding(2);
|
||||
btnRun.Name = "btnRun";
|
||||
btnRun.Size = new Size(112, 34);
|
||||
btnRun.Size = new Size(90, 27);
|
||||
btnRun.TabIndex = 13;
|
||||
btnRun.Text = "Run";
|
||||
btnRun.UseVisualStyleBackColor = true;
|
||||
@@ -167,10 +170,10 @@
|
||||
//
|
||||
// btnRefreshMemory
|
||||
//
|
||||
btnRefreshMemory.Location = new Point(531, 26);
|
||||
btnRefreshMemory.Location = new Point(425, 21);
|
||||
btnRefreshMemory.Margin = new Padding(2);
|
||||
btnRefreshMemory.Name = "btnRefreshMemory";
|
||||
btnRefreshMemory.Size = new Size(112, 34);
|
||||
btnRefreshMemory.Size = new Size(90, 27);
|
||||
btnRefreshMemory.TabIndex = 14;
|
||||
btnRefreshMemory.Text = "Refresh Memory";
|
||||
btnRefreshMemory.UseVisualStyleBackColor = true;
|
||||
@@ -178,39 +181,37 @@
|
||||
//
|
||||
// txtMemoryView
|
||||
//
|
||||
txtMemoryView.Location = new Point(110, 100);
|
||||
txtMemoryView.Location = new Point(88, 80);
|
||||
txtMemoryView.Margin = new Padding(2);
|
||||
txtMemoryView.Name = "txtMemoryView";
|
||||
txtMemoryView.Size = new Size(519, 243);
|
||||
txtMemoryView.Size = new Size(416, 195);
|
||||
txtMemoryView.TabIndex = 15;
|
||||
txtMemoryView.Text = "Memory View Window";
|
||||
//
|
||||
// lstDisassembly
|
||||
//
|
||||
lstDisassembly.FormattingEnabled = true;
|
||||
lstDisassembly.ItemHeight = 25;
|
||||
lstDisassembly.Location = new Point(654, 14);
|
||||
lstDisassembly.Location = new Point(523, 11);
|
||||
lstDisassembly.Margin = new Padding(2);
|
||||
lstDisassembly.Name = "lstDisassembly";
|
||||
lstDisassembly.Size = new Size(314, 329);
|
||||
lstDisassembly.Size = new Size(252, 264);
|
||||
lstDisassembly.TabIndex = 16;
|
||||
//
|
||||
// lstStack
|
||||
//
|
||||
lstStack.FormattingEnabled = true;
|
||||
lstStack.ItemHeight = 25;
|
||||
lstStack.Location = new Point(974, 14);
|
||||
lstStack.Location = new Point(779, 11);
|
||||
lstStack.Margin = new Padding(2);
|
||||
lstStack.Name = "lstStack";
|
||||
lstStack.Size = new Size(162, 329);
|
||||
lstStack.Size = new Size(130, 264);
|
||||
lstStack.TabIndex = 17;
|
||||
//
|
||||
// btnExit
|
||||
//
|
||||
btnExit.Location = new Point(1019, 520);
|
||||
btnExit.Location = new Point(815, 416);
|
||||
btnExit.Margin = new Padding(2);
|
||||
btnExit.Name = "btnExit";
|
||||
btnExit.Size = new Size(112, 34);
|
||||
btnExit.Size = new Size(90, 27);
|
||||
btnExit.TabIndex = 18;
|
||||
btnExit.Text = "Full Exit";
|
||||
btnExit.UseVisualStyleBackColor = true;
|
||||
@@ -219,54 +220,83 @@
|
||||
// label1
|
||||
//
|
||||
label1.AutoSize = true;
|
||||
label1.Location = new Point(361, 360);
|
||||
label1.Margin = new Padding(4, 0, 4, 0);
|
||||
label1.Location = new Point(200, 278);
|
||||
label1.Name = "label1";
|
||||
label1.Size = new Size(97, 25);
|
||||
label1.Size = new Size(81, 20);
|
||||
label1.TabIndex = 19;
|
||||
label1.Text = "Breakpoint";
|
||||
//
|
||||
// txtBreakpoint
|
||||
//
|
||||
txtBreakpoint.Location = new Point(470, 351);
|
||||
txtBreakpoint.Margin = new Padding(4, 4, 4, 4);
|
||||
txtBreakpoint.Location = new Point(376, 281);
|
||||
txtBreakpoint.Name = "txtBreakpoint";
|
||||
txtBreakpoint.Size = new Size(155, 31);
|
||||
txtBreakpoint.Size = new Size(125, 27);
|
||||
txtBreakpoint.TabIndex = 20;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
label2.AutoSize = true;
|
||||
label2.Location = new Point(291, 26);
|
||||
label2.Margin = new Padding(4, 0, 4, 0);
|
||||
label2.Location = new Point(233, 21);
|
||||
label2.Name = "label2";
|
||||
label2.Size = new Size(77, 25);
|
||||
label2.Size = new Size(62, 20);
|
||||
label2.TabIndex = 21;
|
||||
label2.Text = "Address";
|
||||
//
|
||||
// lblIX
|
||||
//
|
||||
lblIX.AutoSize = true;
|
||||
lblIX.Location = new Point(11, 373);
|
||||
lblIX.Location = new Point(9, 298);
|
||||
lblIX.Margin = new Padding(2, 0, 2, 0);
|
||||
lblIX.Name = "lblIX";
|
||||
lblIX.Size = new Size(28, 25);
|
||||
lblIX.Size = new Size(22, 20);
|
||||
lblIX.TabIndex = 22;
|
||||
lblIX.Text = "IX";
|
||||
//
|
||||
// lblIY
|
||||
//
|
||||
lblIY.AutoSize = true;
|
||||
lblIY.Location = new Point(12, 430);
|
||||
lblIY.Location = new Point(10, 344);
|
||||
lblIY.Margin = new Padding(2, 0, 2, 0);
|
||||
lblIY.Name = "lblIY";
|
||||
lblIY.Size = new Size(27, 25);
|
||||
lblIY.Size = new Size(21, 20);
|
||||
lblIY.TabIndex = 23;
|
||||
lblIY.Text = "IY";
|
||||
//
|
||||
// lblIff1
|
||||
//
|
||||
lblIff1.AutoSize = true;
|
||||
lblIff1.Location = new Point(88, 298);
|
||||
lblIff1.Name = "lblIff1";
|
||||
lblIff1.Size = new Size(35, 20);
|
||||
lblIff1.TabIndex = 24;
|
||||
lblIff1.Text = "IFF1";
|
||||
//
|
||||
// lblIff2
|
||||
//
|
||||
lblIff2.AutoSize = true;
|
||||
lblIff2.Location = new Point(88, 345);
|
||||
lblIff2.Name = "lblIff2";
|
||||
lblIff2.Size = new Size(35, 20);
|
||||
lblIff2.TabIndex = 25;
|
||||
lblIff2.Text = "IFF2";
|
||||
//
|
||||
// lblIE
|
||||
//
|
||||
lblIE.AutoSize = true;
|
||||
lblIE.Location = new Point(200, 345);
|
||||
lblIE.Name = "lblIE";
|
||||
lblIE.Size = new Size(109, 20);
|
||||
lblIE.TabIndex = 26;
|
||||
lblIE.Text = "Interrupt Mode";
|
||||
//
|
||||
// DebuggerForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(10F, 25F);
|
||||
AutoScaleDimensions = new SizeF(8F, 20F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1160, 568);
|
||||
ClientSize = new Size(928, 454);
|
||||
Controls.Add(lblIE);
|
||||
Controls.Add(lblIff2);
|
||||
Controls.Add(lblIff1);
|
||||
Controls.Add(lblIY);
|
||||
Controls.Add(lblIX);
|
||||
Controls.Add(label2);
|
||||
@@ -319,6 +349,9 @@
|
||||
private Label label2;
|
||||
private Label lblIX;
|
||||
private Label lblIY;
|
||||
private Label lblIff1;
|
||||
private Label lblIff2;
|
||||
private Label lblIE;
|
||||
//private TextBox textBox4;
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,9 @@ namespace Desktop
|
||||
lblSP.Text = $"SP: {_cpu.SP:X4}";
|
||||
lblIX.Text = $"IX: {_cpu.IX.Word:X4}";
|
||||
lblIY.Text = $"IY: {_cpu.IY.Word:X4}";
|
||||
lblIff1.Text = $"IFF1: {_cpu.IFF1}";
|
||||
lblIff2.Text = $"IFF2: {_cpu.IFF2}";
|
||||
lblIE.Text = $"Interrupt Mode: {_cpu.InterruptMode}";
|
||||
|
||||
// 2. Update Flags & T-States
|
||||
lblFlags.Text = $"Flags: {_cpu.GetFlagsString()}";
|
||||
@@ -232,6 +235,12 @@ namespace Desktop
|
||||
case 0x04:
|
||||
mnemonic = "INC B";
|
||||
break;
|
||||
case 0x10:
|
||||
sbyte djnzOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
|
||||
ushort djnzDest = (ushort)(currentPc + 2 + djnzOffset);
|
||||
mnemonic = $"DJNZ 0x{djnzDest:X4}";
|
||||
instructionLength = 2;
|
||||
break;
|
||||
case 0x11:
|
||||
// LD DE, nn
|
||||
byte deLow = _memoryBus.Read((ushort)(currentPc + 1));
|
||||
@@ -285,6 +294,13 @@ namespace Desktop
|
||||
mnemonic = $"JR NC, 0x{dest:X4}";
|
||||
instructionLength = 2;
|
||||
break;
|
||||
case 0x32:
|
||||
{
|
||||
ushort addr32 = (ushort)(_memoryBus.Read((ushort)(currentPc + 1)) | (_memoryBus.Read((ushort)(currentPc + 2)) << 8));
|
||||
mnemonic = $"LD (0x{addr32:X4}), A";
|
||||
instructionLength = 3;
|
||||
break;
|
||||
}
|
||||
case 0x35:
|
||||
mnemonic = "DEC (HL)";
|
||||
break;
|
||||
@@ -306,6 +322,9 @@ namespace Desktop
|
||||
case 0x6B:
|
||||
mnemonic = "LD L, E";
|
||||
break;
|
||||
case 0x77:
|
||||
mnemonic = "LD (HL), A";
|
||||
break;
|
||||
case 0xA7:
|
||||
mnemonic = "AND A";
|
||||
break;
|
||||
@@ -322,6 +341,11 @@ namespace Desktop
|
||||
mnemonic = $"JP 0x{jpHigh:X2}{jpLow:X2}";
|
||||
instructionLength = 3;
|
||||
break;
|
||||
case 0xCD:
|
||||
ushort callDest = (ushort)(_memoryBus.Read((ushort)(currentPc + 1)) | (_memoryBus.Read((ushort)(currentPc + 2)) << 8));
|
||||
mnemonic = $"CALL 0x{callDest:X4}";
|
||||
instructionLength = 3;
|
||||
break;
|
||||
case 0xD3:
|
||||
byte outPort = _memoryBus.Read((ushort)(currentPc + 1));
|
||||
mnemonic = $"OUT (0x{outPort:X2}), A";
|
||||
@@ -386,6 +410,9 @@ namespace Desktop
|
||||
case 0xF9:
|
||||
mnemonic = "LD SP, HL";
|
||||
break;
|
||||
case 0xFB:
|
||||
mnemonic = "EI";
|
||||
break;
|
||||
case 0xFD:
|
||||
{
|
||||
byte fdOpcode = _memoryBus.Read((ushort)(currentPc + 1));
|
||||
@@ -396,6 +423,36 @@ namespace Desktop
|
||||
mnemonic = $"LD IY, 0x{iyVal:X4}";
|
||||
instructionLength = 4;
|
||||
}
|
||||
else if (fdOpcode == 0x35) // DEC (IY+d)
|
||||
{
|
||||
sbyte d = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
|
||||
string sign = d >= 0 ? "+" : ""; // Gives us a clean + or -
|
||||
mnemonic = $"DEC (IY{sign}{d})";
|
||||
instructionLength = 3;
|
||||
}
|
||||
else if (fdOpcode == 0xCB) // FD CB prefix
|
||||
{
|
||||
sbyte d = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
|
||||
byte cbOpcode = _memoryBus.Read((ushort)(currentPc + 3));
|
||||
string sign = d >= 0 ? "+" : "";
|
||||
|
||||
if (cbOpcode == 0xCE)
|
||||
{
|
||||
mnemonic = $"SET 1, (IY{sign}{d})";
|
||||
}
|
||||
else
|
||||
{
|
||||
mnemonic = $"FD CB {d:X2} {cbOpcode:X2}"; // Fallback
|
||||
}
|
||||
instructionLength = 4;
|
||||
}
|
||||
else if (fdOpcode == 0x75) // LD (IY+d), L
|
||||
{
|
||||
sbyte d = (sbyte)_memoryBus.Read((ushort)(currentPc + 2));
|
||||
string sign = d >= 0 ? "+" : "";
|
||||
mnemonic = $"LD (IY{sign}{d}), L";
|
||||
instructionLength = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
mnemonic = $"FD PREFIX UNKNOWN (0x{fdOpcode:X2})";
|
||||
|
||||
Reference in New Issue
Block a user