More keys. Implemented Border. Completes LOAD readiness sequence

This commit is contained in:
2026-04-18 01:55:08 +01:00
parent 389df3780e
commit 47f3a76bb2
5 changed files with 188 additions and 34 deletions

View File

@@ -1009,6 +1009,17 @@ namespace Core.Cpu
if ((AF.Low & 0x01) != 0) PC = addr;
return 10;
}
case 0xDB: // IN A, (n)
// 1. Fetch the immediate port offset byte
byte portOffsetDB = FetchByte();
// 2. The Z80 puts 'A' on the top 8 bits, and 'n' on the bottom 8 bits
ushort portAddressDB = (ushort)((AF.High << 8) | portOffsetDB);
// 3. Read from the I/O bus and store the result straight into the Accumulator
AF.High = _simpleIoBus.ReadPort(portAddressDB);
return 11;
case 0xE2: // JP PO, nn (Parity Odd / No Overflow)
{
ushort addr = FetchWord();
@@ -1251,7 +1262,7 @@ namespace Core.Cpu
throw new NotImplementedException($"Opcode 0x{opcode:X2} at PC 0x{(PC - 1):X4} is not implemented.");
}
}
private int ExecuteExtendedPrefix()
private int ExecuteExtendedPrefix() //ED
{
// Fetch the actual extended instruction
byte extendedOpcode = _memory.Read(PC++);
@@ -1376,6 +1387,9 @@ namespace Core.Cpu
AF.Low = newFlags;
return 12;
case 0x79: // OUT (C), A
_simpleIoBus.WritePort(BC.Word, AF.High);
return 12; // 12 T-States
case 0x7B: // LD SP, (nn)
// 1. Fetch the absolute 16-bit memory address from the instruction stream
byte addrLow = FetchByte();
@@ -1596,6 +1610,65 @@ namespace Core.Cpu
IX.Word = (ushort)((high << 8) | low);
return 14;
case 0x36: // LD (IX+d), n
// 1. Fetch the displacement byte first
sbyte offset36 = (sbyte)FetchByte();
// 2. Fetch the immediate 8-bit value second
byte n36 = FetchByte();
// 3. Calculate the exact memory address (IX + offset)
ushort address36 = (ushort)(IX.Word + offset36);
// 4. Write the immediate value directly into memory
_memory.Write(address36, n36);
return 19;
case 0x74: // LD (IX+d), H
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset74 = (sbyte)FetchByte();
// 2. Calculate the exact memory address (IX + offset)
ushort address74 = (ushort)(IX.Word + offset74);
// 3. Write the contents of the L register (Low byte of HL) into memory
_memory.Write(address74, HL.High);
return 19;
case 0x75: // LD (IX+d), L
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset75 = (sbyte)FetchByte();
// 2. Calculate the exact memory address (IX + offset)
ushort address75 = (ushort)(IX.Word + offset75);
// 3. Write the contents of the L register (Low byte of HL) into memory
_memory.Write(address75, HL.Low);
return 19;
case 0xE1: // POP IX
// 1. Read the low byte from the top of the stack
byte popLow = _memory.Read(SP);
SP++; // Move stack pointer up
// 2. Read the high byte
byte popHigh = _memory.Read(SP);
SP++; // Move stack pointer up again
// 3. Combine them and store in IX
IX.Word = (ushort)((popHigh << 8) | popLow);
return 14;
case 0xE5: // PUSH IX
// 1. Decrement the stack pointer and write the HIGH byte
SP--;
_memory.Write(SP, IX.High);
// 2. Decrement the stack pointer again and write the LOW byte
SP--;
_memory.Write(SP, IX.Low);
return 15;
case 0xE9: // JP (IX)
PC = IX.Word;
return 8;
@@ -1727,6 +1800,17 @@ namespace Core.Cpu
_memory.Write(targetAddress, BC.Low);
return 19; // Takes 19 T-States
}
case 0x72: // LD (IY+d), D
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset72 = (sbyte)FetchByte();
// 2. Calculate the exact memory address (IY + offset)
ushort address72 = (ushort)(IY.Word + offset72);
// 3. Write the contents of the D register (High byte of DE) into memory
_memory.Write(address72, DE.High);
return 19; // 19 T-States
case 0x74: // LD (IY+d), H
// 1. Fetch the displacement byte and cast it to a signed sbyte
sbyte offset74 = (sbyte)FetchByte();

View File

@@ -5,8 +5,10 @@ namespace Core.Io
{
public class IO_Bus
{
// 8 rows representing the Spectrum keyboard matrix. Default to 0xFF (unpressed).
public byte[] KeyboardRows = new byte[8] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
public byte BorderColorIndex { get; private set; } = 7; // 7 is White
// 8 rows representing the Spectrum keyboard matrix. Default to 0xFF (unpressed).
public byte[] KeyboardRows = new byte[8] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
public byte ReadPort(ushort portAddress)
{
@@ -35,9 +37,17 @@ namespace Core.Io
return 0xFF;
}
public void WritePort(ushort portAddress, byte portValue)
public void WritePort(ushort portAddress, byte portValue)
{
// The ULA intercepts any write to an even port address
if ((portAddress & 0x01) == 0)
{
// The bottom 3 bits (0-2) define the border color!
BorderColorIndex = (byte)(portValue & 0x07);
// (Bits 3 and 4 handle the cassette MIC output and the internal speaker,
// which we will need when we start playing audio!)
}
}
}
}
}