Implemented a load more Z80 OpCodes. Added IX, IY and Interrupts to Debugger

This commit is contained in:
2026-04-13 17:28:41 +01:00
parent c2bbaf7672
commit ed0772f27a
3 changed files with 247 additions and 54 deletions

View File

@@ -11,8 +11,8 @@ namespace Core.Cpu
public int InterruptMode { get; private set; } = 0; // Defaults to 0 on power-up public int InterruptMode { get; private set; } = 0; // Defaults to 0 on power-up
// Interrupt Flip-Flops // Interrupt Flip-Flops
public bool IFF1; public bool IFF1 { get; private set; } = false;
public bool IFF2; public bool IFF2 { get; private set; } = false;
// Main Register Set // Main Register Set
public RegisterPair AF; public RegisterPair AF;
@@ -298,6 +298,17 @@ namespace Core.Cpu
return (bits % 2) == 0; 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) private int ExecuteOpcode(byte opcode)
{ {
sbyte offset = 0; sbyte offset = 0;
@@ -311,6 +322,18 @@ namespace Core.Cpu
case 0x04: // INC B case 0x04: // INC B
BC.High = Inc8(BC.High); BC.High = Inc8(BC.High);
return 4; 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 case 0x11: //LD DE, nn
DE.Word = FetchWord(); DE.Word = FetchWord();
return 10; return 10;
@@ -366,6 +389,12 @@ namespace Core.Cpu
return 12; // Jump taken return 12; // Jump taken
} }
return 7; // Jump not 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) case 0x35: // DEC (HL)
// Read the current byte from memory // Read the current byte from memory
byte memValue = _memory.Read(HL.Word); byte memValue = _memory.Read(HL.Word);
@@ -394,6 +423,9 @@ namespace Core.Cpu
case 0x6B: // LD L, E case 0x6B: // LD L, E
HL.Low = DE.Low; HL.Low = DE.Low;
return 4; return 4;
case 0x77: // LD (HL), A
_memory.Write(HL.Word, AF.High);
return 7;
case 0xA7: // AND A case 0xA7: // AND A
And(AF.High); And(AF.High);
return 4; return 4;
@@ -407,6 +439,11 @@ namespace Core.Cpu
case 0xC3: case 0xC3:
PC = FetchWord(); PC = FetchWord();
return 10; return 10;
case 0xCD: // CALL nn
ushort callAddress = FetchWord();
Push(PC);
PC = callAddress;
return 17;
case 0xD3: // OUT (n), A case 0xD3: // OUT (n), A
byte portOffset = FetchByte(); byte portOffset = FetchByte();
@@ -447,6 +484,10 @@ namespace Core.Cpu
case 0xF9: // LD SP, HL case 0xF9: // LD SP, HL
SP = HL.Word; // (Use SP.Word = HL.Word if you made SP a RegisterPair) SP = HL.Word; // (Use SP.Word = HL.Word if you made SP a RegisterPair)
return 6; return 6;
case 0xFB: // EI
IFF1 = true;
IFF2 = true;
return 4;
case 0xFD: case 0xFD:
return ExecuteFDPrefix(); return ExecuteFDPrefix();
default: default:
@@ -457,6 +498,7 @@ namespace Core.Cpu
{ {
// Fetch the actual extended instruction // Fetch the actual extended instruction
byte extendedOpcode = _memory.Read(PC++); byte extendedOpcode = _memory.Read(PC++);
byte val = 0;
switch (extendedOpcode) switch (extendedOpcode)
{ {
@@ -478,10 +520,37 @@ namespace Core.Cpu
return 20; return 20;
case 0x56: // IM 1 case 0x56: // IM 1
InterruptMode = 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 case 0xB8: // LDDR
// 1. Read byte from (HL) // 1. Read byte from (HL)
byte val = _memory.Read(HL.Word); val = _memory.Read(HL.Word);
// 2. Write byte to (DE) // 2. Write byte to (DE)
_memory.Write(DE.Word, val); _memory.Write(DE.Word, val);
@@ -515,13 +584,47 @@ namespace Core.Cpu
private int ExecuteFDPrefix() private int ExecuteFDPrefix()
{ {
byte opcode = FetchByte(); byte opcode = FetchByte();
ushort targetAddress = 0;
byte memVal = 0;
switch (opcode) switch (opcode)
{ {
case 0x21: // LD IY, nn case 0x21: // LD IY, nn
IY.Word = FetchWord(); 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: default:
throw new NotImplementedException($"FD prefix opcode {opcode:X2} not implemented!"); throw new NotImplementedException($"FD prefix opcode {opcode:X2} not implemented!");
} }

View File

@@ -50,94 +50,97 @@
label2 = new Label(); label2 = new Label();
lblIX = new Label(); lblIX = new Label();
lblIY = new Label(); lblIY = new Label();
lblIff1 = new Label();
lblIff2 = new Label();
lblIE = new Label();
SuspendLayout(); SuspendLayout();
// //
// lblAF // lblAF
// //
lblAF.AutoSize = true; lblAF.AutoSize = true;
lblAF.Location = new Point(12, 9); lblAF.Location = new Point(10, 7);
lblAF.Margin = new Padding(2, 0, 2, 0); lblAF.Margin = new Padding(2, 0, 2, 0);
lblAF.Name = "lblAF"; lblAF.Name = "lblAF";
lblAF.Size = new Size(33, 25); lblAF.Size = new Size(26, 20);
lblAF.TabIndex = 0; lblAF.TabIndex = 0;
lblAF.Text = "AF"; lblAF.Text = "AF";
// //
// lblBC // lblBC
// //
lblBC.AutoSize = true; lblBC.AutoSize = true;
lblBC.Location = new Point(11, 60); lblBC.Location = new Point(9, 48);
lblBC.Margin = new Padding(2, 0, 2, 0); lblBC.Margin = new Padding(2, 0, 2, 0);
lblBC.Name = "lblBC"; lblBC.Name = "lblBC";
lblBC.Size = new Size(33, 25); lblBC.Size = new Size(27, 20);
lblBC.TabIndex = 1; lblBC.TabIndex = 1;
lblBC.Text = "BC"; lblBC.Text = "BC";
// //
// lblDE // lblDE
// //
lblDE.AutoSize = true; lblDE.AutoSize = true;
lblDE.Location = new Point(12, 125); lblDE.Location = new Point(10, 100);
lblDE.Margin = new Padding(2, 0, 2, 0); lblDE.Margin = new Padding(2, 0, 2, 0);
lblDE.Name = "lblDE"; lblDE.Name = "lblDE";
lblDE.Size = new Size(34, 25); lblDE.Size = new Size(28, 20);
lblDE.TabIndex = 2; lblDE.TabIndex = 2;
lblDE.Text = "DE"; lblDE.Text = "DE";
// //
// lblHL // lblHL
// //
lblHL.AutoSize = true; lblHL.AutoSize = true;
lblHL.Location = new Point(12, 188); lblHL.Location = new Point(10, 150);
lblHL.Margin = new Padding(2, 0, 2, 0); lblHL.Margin = new Padding(2, 0, 2, 0);
lblHL.Name = "lblHL"; lblHL.Name = "lblHL";
lblHL.Size = new Size(33, 25); lblHL.Size = new Size(27, 20);
lblHL.TabIndex = 3; lblHL.TabIndex = 3;
lblHL.Text = "HL"; lblHL.Text = "HL";
// //
// lblPC // lblPC
// //
lblPC.AutoSize = true; lblPC.AutoSize = true;
lblPC.Location = new Point(11, 250); lblPC.Location = new Point(9, 200);
lblPC.Margin = new Padding(2, 0, 2, 0); lblPC.Margin = new Padding(2, 0, 2, 0);
lblPC.Name = "lblPC"; lblPC.Name = "lblPC";
lblPC.Size = new Size(33, 25); lblPC.Size = new Size(26, 20);
lblPC.TabIndex = 4; lblPC.TabIndex = 4;
lblPC.Text = "PC"; lblPC.Text = "PC";
// //
// lblSP // lblSP
// //
lblSP.AutoSize = true; lblSP.AutoSize = true;
lblSP.Location = new Point(11, 315); lblSP.Location = new Point(9, 252);
lblSP.Margin = new Padding(2, 0, 2, 0); lblSP.Margin = new Padding(2, 0, 2, 0);
lblSP.Name = "lblSP"; lblSP.Name = "lblSP";
lblSP.Size = new Size(32, 25); lblSP.Size = new Size(25, 20);
lblSP.TabIndex = 6; lblSP.TabIndex = 6;
lblSP.Text = "SP"; lblSP.Text = "SP";
// //
// lblFlags // lblFlags
// //
lblFlags.AutoSize = true; lblFlags.AutoSize = true;
lblFlags.Location = new Point(110, 65); lblFlags.Location = new Point(88, 52);
lblFlags.Margin = new Padding(2, 0, 2, 0); lblFlags.Margin = new Padding(2, 0, 2, 0);
lblFlags.Name = "lblFlags"; lblFlags.Name = "lblFlags";
lblFlags.Size = new Size(53, 25); lblFlags.Size = new Size(43, 20);
lblFlags.TabIndex = 7; lblFlags.TabIndex = 7;
lblFlags.Text = "Flags"; lblFlags.Text = "Flags";
// //
// lblTStates // lblTStates
// //
lblTStates.AutoSize = true; lblTStates.AutoSize = true;
lblTStates.Location = new Point(110, 9); lblTStates.Location = new Point(88, 7);
lblTStates.Margin = new Padding(2, 0, 2, 0); lblTStates.Margin = new Padding(2, 0, 2, 0);
lblTStates.Name = "lblTStates"; lblTStates.Name = "lblTStates";
lblTStates.Size = new Size(75, 25); lblTStates.Size = new Size(63, 20);
lblTStates.TabIndex = 8; lblTStates.TabIndex = 8;
lblTStates.Text = "T-States"; lblTStates.Text = "T-States";
// //
// txtMemoryStart // txtMemoryStart
// //
txtMemoryStart.Location = new Point(375, 26); txtMemoryStart.Location = new Point(300, 21);
txtMemoryStart.Margin = new Padding(2); txtMemoryStart.Margin = new Padding(2);
txtMemoryStart.Name = "txtMemoryStart"; txtMemoryStart.Name = "txtMemoryStart";
txtMemoryStart.Size = new Size(150, 31); txtMemoryStart.Size = new Size(121, 27);
txtMemoryStart.TabIndex = 9; txtMemoryStart.TabIndex = 9;
txtMemoryStart.Text = "Memory Start"; txtMemoryStart.Text = "Memory Start";
txtMemoryStart.TextAlign = HorizontalAlignment.Center; txtMemoryStart.TextAlign = HorizontalAlignment.Center;
@@ -145,10 +148,10 @@
// //
// btnStep // btnStep
// //
btnStep.Location = new Point(8, 523); btnStep.Location = new Point(6, 418);
btnStep.Margin = new Padding(2); btnStep.Margin = new Padding(2);
btnStep.Name = "btnStep"; btnStep.Name = "btnStep";
btnStep.Size = new Size(112, 34); btnStep.Size = new Size(90, 27);
btnStep.TabIndex = 12; btnStep.TabIndex = 12;
btnStep.Text = "Step"; btnStep.Text = "Step";
btnStep.UseVisualStyleBackColor = true; btnStep.UseVisualStyleBackColor = true;
@@ -156,10 +159,10 @@
// //
// btnRun // btnRun
// //
btnRun.Location = new Point(149, 523); btnRun.Location = new Point(119, 418);
btnRun.Margin = new Padding(2); btnRun.Margin = new Padding(2);
btnRun.Name = "btnRun"; btnRun.Name = "btnRun";
btnRun.Size = new Size(112, 34); btnRun.Size = new Size(90, 27);
btnRun.TabIndex = 13; btnRun.TabIndex = 13;
btnRun.Text = "Run"; btnRun.Text = "Run";
btnRun.UseVisualStyleBackColor = true; btnRun.UseVisualStyleBackColor = true;
@@ -167,10 +170,10 @@
// //
// btnRefreshMemory // btnRefreshMemory
// //
btnRefreshMemory.Location = new Point(531, 26); btnRefreshMemory.Location = new Point(425, 21);
btnRefreshMemory.Margin = new Padding(2); btnRefreshMemory.Margin = new Padding(2);
btnRefreshMemory.Name = "btnRefreshMemory"; btnRefreshMemory.Name = "btnRefreshMemory";
btnRefreshMemory.Size = new Size(112, 34); btnRefreshMemory.Size = new Size(90, 27);
btnRefreshMemory.TabIndex = 14; btnRefreshMemory.TabIndex = 14;
btnRefreshMemory.Text = "Refresh Memory"; btnRefreshMemory.Text = "Refresh Memory";
btnRefreshMemory.UseVisualStyleBackColor = true; btnRefreshMemory.UseVisualStyleBackColor = true;
@@ -178,39 +181,37 @@
// //
// txtMemoryView // txtMemoryView
// //
txtMemoryView.Location = new Point(110, 100); txtMemoryView.Location = new Point(88, 80);
txtMemoryView.Margin = new Padding(2); txtMemoryView.Margin = new Padding(2);
txtMemoryView.Name = "txtMemoryView"; txtMemoryView.Name = "txtMemoryView";
txtMemoryView.Size = new Size(519, 243); txtMemoryView.Size = new Size(416, 195);
txtMemoryView.TabIndex = 15; txtMemoryView.TabIndex = 15;
txtMemoryView.Text = "Memory View Window"; txtMemoryView.Text = "Memory View Window";
// //
// lstDisassembly // lstDisassembly
// //
lstDisassembly.FormattingEnabled = true; lstDisassembly.FormattingEnabled = true;
lstDisassembly.ItemHeight = 25; lstDisassembly.Location = new Point(523, 11);
lstDisassembly.Location = new Point(654, 14);
lstDisassembly.Margin = new Padding(2); lstDisassembly.Margin = new Padding(2);
lstDisassembly.Name = "lstDisassembly"; lstDisassembly.Name = "lstDisassembly";
lstDisassembly.Size = new Size(314, 329); lstDisassembly.Size = new Size(252, 264);
lstDisassembly.TabIndex = 16; lstDisassembly.TabIndex = 16;
// //
// lstStack // lstStack
// //
lstStack.FormattingEnabled = true; lstStack.FormattingEnabled = true;
lstStack.ItemHeight = 25; lstStack.Location = new Point(779, 11);
lstStack.Location = new Point(974, 14);
lstStack.Margin = new Padding(2); lstStack.Margin = new Padding(2);
lstStack.Name = "lstStack"; lstStack.Name = "lstStack";
lstStack.Size = new Size(162, 329); lstStack.Size = new Size(130, 264);
lstStack.TabIndex = 17; lstStack.TabIndex = 17;
// //
// btnExit // btnExit
// //
btnExit.Location = new Point(1019, 520); btnExit.Location = new Point(815, 416);
btnExit.Margin = new Padding(2); btnExit.Margin = new Padding(2);
btnExit.Name = "btnExit"; btnExit.Name = "btnExit";
btnExit.Size = new Size(112, 34); btnExit.Size = new Size(90, 27);
btnExit.TabIndex = 18; btnExit.TabIndex = 18;
btnExit.Text = "Full Exit"; btnExit.Text = "Full Exit";
btnExit.UseVisualStyleBackColor = true; btnExit.UseVisualStyleBackColor = true;
@@ -219,54 +220,83 @@
// label1 // label1
// //
label1.AutoSize = true; label1.AutoSize = true;
label1.Location = new Point(361, 360); label1.Location = new Point(200, 278);
label1.Margin = new Padding(4, 0, 4, 0);
label1.Name = "label1"; label1.Name = "label1";
label1.Size = new Size(97, 25); label1.Size = new Size(81, 20);
label1.TabIndex = 19; label1.TabIndex = 19;
label1.Text = "Breakpoint"; label1.Text = "Breakpoint";
// //
// txtBreakpoint // txtBreakpoint
// //
txtBreakpoint.Location = new Point(470, 351); txtBreakpoint.Location = new Point(376, 281);
txtBreakpoint.Margin = new Padding(4, 4, 4, 4);
txtBreakpoint.Name = "txtBreakpoint"; txtBreakpoint.Name = "txtBreakpoint";
txtBreakpoint.Size = new Size(155, 31); txtBreakpoint.Size = new Size(125, 27);
txtBreakpoint.TabIndex = 20; txtBreakpoint.TabIndex = 20;
// //
// label2 // label2
// //
label2.AutoSize = true; label2.AutoSize = true;
label2.Location = new Point(291, 26); label2.Location = new Point(233, 21);
label2.Margin = new Padding(4, 0, 4, 0);
label2.Name = "label2"; label2.Name = "label2";
label2.Size = new Size(77, 25); label2.Size = new Size(62, 20);
label2.TabIndex = 21; label2.TabIndex = 21;
label2.Text = "Address"; label2.Text = "Address";
// //
// lblIX // lblIX
// //
lblIX.AutoSize = true; 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.Name = "lblIX";
lblIX.Size = new Size(28, 25); lblIX.Size = new Size(22, 20);
lblIX.TabIndex = 22; lblIX.TabIndex = 22;
lblIX.Text = "IX"; lblIX.Text = "IX";
// //
// lblIY // lblIY
// //
lblIY.AutoSize = true; 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.Name = "lblIY";
lblIY.Size = new Size(27, 25); lblIY.Size = new Size(21, 20);
lblIY.TabIndex = 23; lblIY.TabIndex = 23;
lblIY.Text = "IY"; 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 // DebuggerForm
// //
AutoScaleDimensions = new SizeF(10F, 25F); AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font; 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(lblIY);
Controls.Add(lblIX); Controls.Add(lblIX);
Controls.Add(label2); Controls.Add(label2);
@@ -319,6 +349,9 @@
private Label label2; private Label label2;
private Label lblIX; private Label lblIX;
private Label lblIY; private Label lblIY;
private Label lblIff1;
private Label lblIff2;
private Label lblIE;
//private TextBox textBox4; //private TextBox textBox4;
} }
} }

View File

@@ -134,6 +134,9 @@ namespace Desktop
lblSP.Text = $"SP: {_cpu.SP:X4}"; lblSP.Text = $"SP: {_cpu.SP:X4}";
lblIX.Text = $"IX: {_cpu.IX.Word:X4}"; lblIX.Text = $"IX: {_cpu.IX.Word:X4}";
lblIY.Text = $"IY: {_cpu.IY.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 // 2. Update Flags & T-States
lblFlags.Text = $"Flags: {_cpu.GetFlagsString()}"; lblFlags.Text = $"Flags: {_cpu.GetFlagsString()}";
@@ -232,6 +235,12 @@ namespace Desktop
case 0x04: case 0x04:
mnemonic = "INC B"; mnemonic = "INC B";
break; 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: case 0x11:
// LD DE, nn // LD DE, nn
byte deLow = _memoryBus.Read((ushort)(currentPc + 1)); byte deLow = _memoryBus.Read((ushort)(currentPc + 1));
@@ -285,6 +294,13 @@ namespace Desktop
mnemonic = $"JR NC, 0x{dest:X4}"; mnemonic = $"JR NC, 0x{dest:X4}";
instructionLength = 2; instructionLength = 2;
break; 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: case 0x35:
mnemonic = "DEC (HL)"; mnemonic = "DEC (HL)";
break; break;
@@ -306,6 +322,9 @@ namespace Desktop
case 0x6B: case 0x6B:
mnemonic = "LD L, E"; mnemonic = "LD L, E";
break; break;
case 0x77:
mnemonic = "LD (HL), A";
break;
case 0xA7: case 0xA7:
mnemonic = "AND A"; mnemonic = "AND A";
break; break;
@@ -322,6 +341,11 @@ namespace Desktop
mnemonic = $"JP 0x{jpHigh:X2}{jpLow:X2}"; mnemonic = $"JP 0x{jpHigh:X2}{jpLow:X2}";
instructionLength = 3; instructionLength = 3;
break; 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: case 0xD3:
byte outPort = _memoryBus.Read((ushort)(currentPc + 1)); byte outPort = _memoryBus.Read((ushort)(currentPc + 1));
mnemonic = $"OUT (0x{outPort:X2}), A"; mnemonic = $"OUT (0x{outPort:X2}), A";
@@ -386,6 +410,9 @@ namespace Desktop
case 0xF9: case 0xF9:
mnemonic = "LD SP, HL"; mnemonic = "LD SP, HL";
break; break;
case 0xFB:
mnemonic = "EI";
break;
case 0xFD: case 0xFD:
{ {
byte fdOpcode = _memoryBus.Read((ushort)(currentPc + 1)); byte fdOpcode = _memoryBus.Read((ushort)(currentPc + 1));
@@ -396,6 +423,36 @@ namespace Desktop
mnemonic = $"LD IY, 0x{iyVal:X4}"; mnemonic = $"LD IY, 0x{iyVal:X4}";
instructionLength = 4; 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 else
{ {
mnemonic = $"FD PREFIX UNKNOWN (0x{fdOpcode:X2})"; mnemonic = $"FD PREFIX UNKNOWN (0x{fdOpcode:X2})";