From 096eacc0482f910f920cd49a5721bdf47370d136 Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Mon, 21 Jul 2025 22:57:36 +0200 Subject: [PATCH 1/9] Memory separated from CPU class --- CPU_emu/Class_CPU.cs | 26 +++++------- CPU_emu/Forms/CPU_emu.cs | 37 +++++++++++++---- CPU_emu/Interfaces/IMemoryBus.cs | 2 +- CPU_emu/MemoryBus.cs | 43 -------------------- CPU_emu/MemoryBus/IoDevice.cs | 31 ++++++++++++++ CPU_emu/MemoryBus/MappedBus.cs | 70 ++++++++++++++++++++++++++++++++ CPU_emu/MemoryBus/RamBus.cs | 43 ++++++++++++++++++++ CPU_emu/MemoryBus/RomBus.cs | 51 +++++++++++++++++++++++ CPU_emuTests/CPU_Tests.cs | 45 +++++++++++++++++--- 9 files changed, 277 insertions(+), 71 deletions(-) delete mode 100644 CPU_emu/MemoryBus.cs create mode 100644 CPU_emu/MemoryBus/IoDevice.cs create mode 100644 CPU_emu/MemoryBus/MappedBus.cs create mode 100644 CPU_emu/MemoryBus/RamBus.cs create mode 100644 CPU_emu/MemoryBus/RomBus.cs diff --git a/CPU_emu/Class_CPU.cs b/CPU_emu/Class_CPU.cs index 068594f..a1d9e4e 100644 --- a/CPU_emu/Class_CPU.cs +++ b/CPU_emu/Class_CPU.cs @@ -32,7 +32,7 @@ public partial class CPU private const uint MAX_MEM = 1024 * 64; private byte[] Data = new byte[MAX_MEM]; - MemoryBus _memoryBus; + MappedBus _memoryBus; private byte NegativeFlagBit = 0b10000000, @@ -51,12 +51,13 @@ public byte[] Memory { get { - return Data; + return _memoryBus.Dump(0,_memoryBus.RamSize); } set { Data = value; + _memoryBus.Load(0,value); OnMemoryUpdate?.Invoke(this, new CPUEventArgs(this)); } } @@ -73,9 +74,10 @@ public byte[] Memory public event EventHandler OnPCoverflow; public event EventHandler OnBreak; - public CPU() + public CPU(MappedBus memoryBus) { - _memoryBus = new MemoryBus(ref Data); + //_memoryBus = new MemoryBus(ref Data); + _memoryBus = memoryBus; SetVectors(); } @@ -222,7 +224,6 @@ private void SetZeroAndNegativeFlags(byte register) private byte FetchByte() { - //byte data = Data[PC]; byte data = _memoryBus.Read((ushort)PC); IncrementPC(); IncrementCpuCycle(1); @@ -242,15 +243,13 @@ private ushort FetchWord(ref ulong CpuCycle) public void WriteByteToMemory(byte b,ushort address) { - //Data[address] = b; _memoryBus.Write(address, b); OnMemoryUpdate?.Invoke(this, new CPUEventArgs(this)); } private byte ReadByteFromMemory(ushort address) { - //return Data[address]; - return _memoryBus.Read(address); + return _memoryBus.Read(address); } private ushort ReadWordFromMemory(ushort address) @@ -337,10 +336,7 @@ public void SetRegister(string regname, byte value) //UT public void ResetMemory() { - for (int i = 0; i < MAX_MEM; i++) - { - Data[i] = 0x00; - } + _memoryBus.EraseRam(); SetVectors(); @@ -348,14 +344,14 @@ public void ResetMemory() } public byte[] ReadMemory() { - return Data; + return _memoryBus.DumpRam(); } internal void UpdateMemoryRange(byte[] data, int startAddress) { for (int i = 0; i < data.Length; i++) { - Memory[startAddress + i] = data[i]; + _memoryBus.Write((ushort)(startAddress + i), data[i]); } OnMemoryUpdate?.Invoke(this, new CPUEventArgs(this)); @@ -364,7 +360,7 @@ internal void UpdateMemoryRange(byte[] data, int startAddress) public class CPUEventArgs : EventArgs { - CPU cpu = new CPU(); + CPU cpu; public string Message { get; set; } public byte[] Memory { get; set; } diff --git a/CPU_emu/Forms/CPU_emu.cs b/CPU_emu/Forms/CPU_emu.cs index c5885d8..c9dbbbd 100644 --- a/CPU_emu/Forms/CPU_emu.cs +++ b/CPU_emu/Forms/CPU_emu.cs @@ -1,4 +1,5 @@ using Bulb; +using CPU_emu; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -9,6 +10,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; +using static System.Runtime.InteropServices.JavaScript.JSType; namespace CPU_emulator @@ -27,12 +29,30 @@ public partial class CPU_emu : Form private ConfigSettings config = new ConfigSettings(); private string _configFilePath = Application.StartupPath + Path.DirectorySeparatorChar + "Data" + Path.DirectorySeparatorChar + "config.json"; + private byte[] _data = new byte[65536]; + private RamBus ram; + private RomBus basicRom; + private RomBus kernalRom; + private IoDevice ioDevice; + public CPU_emu() { //CheckForIllegalCrossThreadCalls = false; InitializeComponent(); - Cpu = new CPU(); + ram = new RamBus(_data); + //var basicRom = new RomBus(File.ReadAllBytes("basic.rom"), 0xA000); + //var kernalRom = new RomBus(File.ReadAllBytes("kernal.rom"), 0xE000); + + basicRom = new RomBus(new byte[1024 * 8], 0xA000); + kernalRom = new RomBus(new byte[1024 * 8], 0xE000); + + ioDevice = new IoDevice(); + + MappedBus memoryBus = new MappedBus(ram, basicRom, kernalRom, ioDevice); + + + Cpu = new CPU(memoryBus); Cpu.OnFlagsUpdate += Cpu_onFlagsUpdate; Cpu.OnMemoryUpdate += Cpu_OnMemoryUpdate; Cpu.OnRegisterUpdate += Cpu_OnRegisterUpdate; @@ -42,6 +62,8 @@ public CPU_emu() Cpu.OnBreak += Cpu_OnBreak; Cpu.OnCpuCycleIncrement += Cpu_OnCpuCycleIncrement; + + Cpu.Reset(); // config.OnPropertyChanged gets initialized @ CPU_emu_Load() due to race conditions @@ -392,7 +414,8 @@ private void SaveMemoryToFile(string fileName) try { fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write); - fs.Write(Cpu.Memory, 0, Cpu.Memory.Length); + //fs.Write(Cpu.Memory, 0, Cpu.Memory.Length); + fs.Write(ram.Dump(0, ram.RamSize)); fs.Close(); } @@ -477,10 +500,10 @@ private void LoadMemoryFromFile(string fileName,int insertIndex) fs = File.OpenRead(fileName); //Debug.Print(fs.Length.ToString()); //Debug.Print(Cpu.Memory.Length.ToString()); - if (fs.Length <= Cpu.Memory.Length) + if (fs.Length <= ram.RamSize) { mem = new byte[fs.Length]; - tmpCpuMem = new byte[Cpu.Memory.Length]; + tmpCpuMem = new byte[ram.RamSize]; tmpCpuMem = Cpu.Memory; fs.Read(mem, 0, (int)fs.Length); @@ -495,15 +518,15 @@ private void LoadMemoryFromFile(string fileName,int insertIndex) { StringBuilder ErrorMessage = new StringBuilder(); ErrorMessage.AppendLine("File is too large"); - ErrorMessage.AppendLine("File has " + fs.Length.ToString() + "bytes."); - ErrorMessage.AppendLine("Max allowed size is " + Cpu.Memory.Length.ToString() + " bytes."); + ErrorMessage.AppendLine($"File has {fs.Length.ToString()} bytes."); + ErrorMessage.AppendLine($"Max allowed size is {ram.RamSize} bytes."); MessageBox.Show(ErrorMessage.ToString(), "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } catch (Exception e) { - MessageBox.Show(e.Message + "\n---\n" + e.InnerException.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(e.Message + "\n---\n" , "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); UseWaitCursor = false; throw; } diff --git a/CPU_emu/Interfaces/IMemoryBus.cs b/CPU_emu/Interfaces/IMemoryBus.cs index 7149b5f..29ef61a 100644 --- a/CPU_emu/Interfaces/IMemoryBus.cs +++ b/CPU_emu/Interfaces/IMemoryBus.cs @@ -6,7 +6,7 @@ namespace CPU_emu; -internal interface IMemoryBus +public interface IMemoryBus { byte Read(ushort address); void Write(ushort address, byte value); diff --git a/CPU_emu/MemoryBus.cs b/CPU_emu/MemoryBus.cs deleted file mode 100644 index 83c6312..0000000 --- a/CPU_emu/MemoryBus.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CPU_emu -{ - internal class MemoryBus : IMemoryBus - { - private readonly byte[] _memory; - - public MemoryBus(int memSize = 1024 * 64) - { - _memory = new byte[memSize]; - } - public MemoryBus(ref byte[] memory) - { - _memory = memory; - } - public byte Read(ushort address) - { - return _memory[address]; - } - - public void Write(ushort address, byte value) - { - _memory[address] = value; - } - - public void Load(ushort address, params byte[] data) - { - Array.Copy(data, 0, _memory, address, data.Length); - } - - public byte[] Dump(ushort address, int length) - { - return _memory.Skip(address).Take(length).ToArray(); - } - - - } -} diff --git a/CPU_emu/MemoryBus/IoDevice.cs b/CPU_emu/MemoryBus/IoDevice.cs new file mode 100644 index 0000000..e3aef73 --- /dev/null +++ b/CPU_emu/MemoryBus/IoDevice.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPU_emu; + +public class IoDevice : IMemoryBus +{ + public byte[] Dump(ushort address, int length) + { + throw new NotImplementedException(); + } + + public void Load(ushort address, params byte[] data) + { + throw new NotImplementedException(); + } + + public byte Read(ushort address) + { + Console.WriteLine($"[IO READ] from ${address:X4}"); + return 0xFF; // Dummy-Value + } + + public void Write(ushort address, byte value) + { + Console.WriteLine($"[IO WRITE] to ${address:X4} = ${value:X2}"); + } +} diff --git a/CPU_emu/MemoryBus/MappedBus.cs b/CPU_emu/MemoryBus/MappedBus.cs new file mode 100644 index 0000000..b8ad25f --- /dev/null +++ b/CPU_emu/MemoryBus/MappedBus.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPU_emu; + +public class MappedBus : IMemoryBus +{ + + private readonly RamBus _ram; + private readonly RomBus _basicRom; + private readonly RomBus _kernalRom; + private readonly IoDevice _io; + + public int RamSize + { + get { return _ram.RamSize; } + } + + public MappedBus(RamBus ram, RomBus basicRom, RomBus kernalRom, IoDevice io) + { + _ram = ram; + _basicRom = basicRom; + _kernalRom = kernalRom; + _io = io; + } + + public void EraseRam() + { + _ram.Load(0,new byte[_ram.RamSize]); + } + + public byte[] Dump(ushort address, int length) + { + return _ram.Dump(address, length); + } + + public byte[] DumpRam() + { + return _ram.Dump(0, _ram.RamSize); + } + + public void Load(ushort address, params byte[] data) + { + _ram.Load(0, data); + } + + public byte Read(ushort address) + { + //if (address >= 0xA000 && address <= 0xBFFF) + // return _basicRom.Read(address); + //else if (address >= 0xD000 && address <= 0xDFFF) + // return _io.Read(address); + //else if (address >= 0xE000) + // return _kernalRom.Read(address); + //else + return _ram.Read(address); + } + + public void Write(ushort address, byte value) + { + //if (address >= 0xD000 && address <= 0xDFFF) + // _io.Write(address, value); + //else if (address < 0xA000 || (address >= 0xC000 && address < 0xD000)) + _ram.Write(address, value); + // Writes to ROM are ignored + } +} diff --git a/CPU_emu/MemoryBus/RamBus.cs b/CPU_emu/MemoryBus/RamBus.cs new file mode 100644 index 0000000..6574be4 --- /dev/null +++ b/CPU_emu/MemoryBus/RamBus.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPU_emu; + +public class RamBus : IMemoryBus +{ + private readonly byte[] _memory; + + public int RamSize + { + get { return _memory.Length; } + } + + public RamBus(byte[] memory) + { + _memory = memory; + } + public byte Read(ushort address) + { + return _memory[address]; + } + + public void Write(ushort address, byte value) + { + _memory[address] = value; + } + + public void Load(ushort address, params byte[] data) + { + Array.Copy(data, 0, _memory, address, data.Length); + } + + public byte[] Dump(ushort address, int length) + { + return _memory.Skip(address).Take(length).ToArray(); + } + + +} diff --git a/CPU_emu/MemoryBus/RomBus.cs b/CPU_emu/MemoryBus/RomBus.cs new file mode 100644 index 0000000..8951f16 --- /dev/null +++ b/CPU_emu/MemoryBus/RomBus.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPU_emu; + +public class RomBus : IMemoryBus +{ + + private readonly byte[] _rom; + private readonly ushort _base; + + public RomBus(byte[] rom, ushort baseAddress = 0) + { + _rom = rom; + _base = baseAddress; + } + + /// + /// + /// + /// Start dump at this address + /// Dump 'length' bytes + /// byte[] + public byte[] Dump(ushort address, int length) + { + return _rom.Skip(address).Take(length).ToArray(); + } + + public void Load(ushort address, params byte[] data) + { + // No load. It's a ROM + } + + /// + /// + /// + /// Address t read + /// byte + public byte Read(ushort address) + { + return _rom[address - _base]; + } + + public void Write(ushort address, byte value) + { + // No write. It's am ROM ;-) + } +} diff --git a/CPU_emuTests/CPU_Tests.cs b/CPU_emuTests/CPU_Tests.cs index 8745d51..d54be35 100644 --- a/CPU_emuTests/CPU_Tests.cs +++ b/CPU_emuTests/CPU_Tests.cs @@ -1,4 +1,5 @@ +using CPU_emu; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection; using System.Reflection; @@ -9,13 +10,30 @@ namespace CPU_emulator; public class CPU_Tests { private CPU cpu; - + private RamBus ram; + private RomBus basicRom; + private RomBus kernalRom; + private IoDevice ioDevice; + private byte[] _data = new byte[65536]; + [SetUp] public void Setup() { - cpu = new CPU(); + InitializeMemory(); + MappedBus memoryBus = new MappedBus(ram, basicRom, kernalRom, ioDevice); + cpu = new CPU(memoryBus); } - + + private void InitializeMemory() + { + ram = new RamBus(_data); + //var basicRom = new RomBus(File.ReadAllBytes("basic.rom"), 0xA000); + //var kernalRom = new RomBus(File.ReadAllBytes("kernal.rom"), 0xE000); + basicRom = new RomBus(new byte[1024 * 8], 0xA000); + kernalRom = new RomBus(new byte[1024 * 8], 0xE000); + ioDevice = new IoDevice(); + } + #region set registers [Test] @@ -321,11 +339,28 @@ public void DecrementSP_Test() public class CPU_Command_Tests { private CPU cpu; + private RamBus ram; + private RomBus basicRom; + private RomBus kernalRom; + private IoDevice ioDevice; + private byte[] _data = new byte[65536]; [SetUp] - public void SetUp() + public void Setup() + { + InitializeMemory(); + MappedBus memoryBus = new MappedBus(ram, basicRom, kernalRom, ioDevice); + cpu = new CPU(memoryBus); + } + + private void InitializeMemory() { - cpu = new CPU(); + ram = new RamBus(_data); + //var basicRom = new RomBus(File.ReadAllBytes("basic.rom"), 0xA000); + //var kernalRom = new RomBus(File.ReadAllBytes("kernal.rom"), 0xE000); + basicRom = new RomBus(new byte[1024 * 8], 0xA000); + kernalRom = new RomBus(new byte[1024 * 8], 0xE000); + ioDevice = new IoDevice(); } #region LDA From 497d506923d38f9a303f6f4dbcdf833456679d62 Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Tue, 22 Jul 2025 08:01:35 +0200 Subject: [PATCH 2/9] tidy up --- CPU_emu/Class_CPU.cs | 79 +++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/CPU_emu/Class_CPU.cs b/CPU_emu/Class_CPU.cs index a1d9e4e..ba469e0 100644 --- a/CPU_emu/Class_CPU.cs +++ b/CPU_emu/Class_CPU.cs @@ -13,11 +13,11 @@ namespace CPU_emulator; public partial class CPU { - + public uint PC { get; set; } = 0xFFFC; // ProgramCounter public bool SlowDown { get; set; } = false; public int SlowDownTime { get; set; } = 750; // - + public ushort SP; // StackPointer public byte A, X, Y; // registers private ushort ResetVector = 0xFFFC; @@ -29,16 +29,16 @@ public partial class CPU private bool _ExitRequested; private bool _SteppingMode; internal ulong _CpuCycle; - private const uint MAX_MEM = 1024 * 64; - private byte[] Data = new byte[MAX_MEM]; + //private const uint MAX_MEM = 1024 * 64; + //private byte[] Data = new byte[MAX_MEM]; MappedBus _memoryBus; private byte NegativeFlagBit = 0b10000000, OverflowFlagBit = 0b01000000, - BreakFlagBit = 0b000010000, - UnusedFlagBit = 0b000100000, + BreakFlagBit = 0b000010000, + UnusedFlagBit = 0b000100000, InterruptDisableFlagBit = 0b000000100, ZeroBit = 0b00000001; @@ -51,13 +51,13 @@ public byte[] Memory { get { - return _memoryBus.Dump(0,_memoryBus.RamSize); + return _memoryBus.Dump(0, _memoryBus.RamSize); } set { - Data = value; - _memoryBus.Load(0,value); + //Data = value; + _memoryBus.Load(0, value); OnMemoryUpdate?.Invoke(this, new CPUEventArgs(this)); } } @@ -65,16 +65,16 @@ public byte[] Memory //public uint PC { get => pC; set => pC = value; } //public uint InitialPC { get => _initialPC; set => _initialPC = value; } - public event EventHandler OnFlagsUpdate; - public event EventHandler OnMemoryUpdate; - public event EventHandler OnRegisterUpdate; - public event EventHandler OnCpuCycleIncrement; - public event EventHandler OnProgramCounterUpdate; - public event EventHandler OnStackPointerUpdate; - public event EventHandler OnPCoverflow; - public event EventHandler OnBreak; - - public CPU(MappedBus memoryBus) + public event EventHandler? OnFlagsUpdate; + public event EventHandler? OnMemoryUpdate; + public event EventHandler? OnRegisterUpdate; + public event EventHandler? OnCpuCycleIncrement; + public event EventHandler? OnProgramCounterUpdate; + public event EventHandler? OnStackPointerUpdate; + public event EventHandler? OnPCoverflow; + public event EventHandler? OnBreak; + + public CPU(MappedBus memoryBus) { //_memoryBus = new MemoryBus(ref Data); _memoryBus = memoryBus; @@ -99,7 +99,7 @@ public void Reset() SetRegister("A", 0); SetRegister("X", 0); SetRegister("Y", 0); - + ExitRequested = false; // set all status flags to false @@ -113,24 +113,24 @@ public void Reset() } - + public void Start() { ExitRequested = false; - + var CpuRunner = new BackgroundWorker(); CpuRunner.DoWork += CpuRunner_DoWork; CpuRunner.RunWorkerAsync(); } - + private void CpuRunner_DoWork(object sender, DoWorkEventArgs e) { - + Type thisType = this.GetType(); - + while (CpuIsRunning) { byte instruction = FetchByte(); @@ -145,7 +145,7 @@ private void CpuRunner_DoWork(object sender, DoWorkEventArgs e) { break; } - if (PC >= MAX_MEM) + if (PC >= _memoryBus.RamSize) { OnPCoverflow?.Invoke(this, new CPUEventArgs(this)); break; @@ -200,13 +200,13 @@ private byte PullByteFromStack(ref ulong CpuCycle) return b; } - private void PushByteToStack(byte b,ref ulong CpuCycle) + private void PushByteToStack(byte b, ref ulong CpuCycle) { WriteByteToMemory(b, SP); IncrementCpuCycle(1); DecrementSP(); IncrementCpuCycle(1); - + } public void Stop() @@ -241,7 +241,7 @@ private ushort FetchWord(ref ulong CpuCycle) return LoByte |= HiByte; } - public void WriteByteToMemory(byte b,ushort address) + public void WriteByteToMemory(byte b, ushort address) { _memoryBus.Write(address, b); OnMemoryUpdate?.Invoke(this, new CPUEventArgs(this)); @@ -249,20 +249,15 @@ public void WriteByteToMemory(byte b,ushort address) private byte ReadByteFromMemory(ushort address) { - return _memoryBus.Read(address); + return _memoryBus.Read(address); } private ushort ReadWordFromMemory(ushort address) { - //ushort tmpPC = ReadByteFromMemory(ResetVector); - //ResetVector++; - //tmpPC |= (ushort)(ReadByteFromMemory(ResetVector) << 8); - - ushort LoByte = ReadByteFromMemory(address); address++; - ushort HiByte = (ushort)(ReadByteFromMemory(address) <<8); - + ushort HiByte = (ushort)(ReadByteFromMemory(address) << 8); + return LoByte |= HiByte; } @@ -292,7 +287,7 @@ private void IncrementCpuCycle(ulong count) private void ResetCpuCycle() { - _CpuCycle =0; + _CpuCycle = 0; OnCpuCycleIncrement?.Invoke(this, new CPUEventArgs(this)); } @@ -313,8 +308,8 @@ public void DecrementPC() PC--; OnProgramCounterUpdate?.Invoke(this, new CPUEventArgs(this)); } - - //UT + + public void SetRegister(string regname, byte value) { switch (regname) @@ -333,7 +328,7 @@ public void SetRegister(string regname, byte value) } OnRegisterUpdate?.Invoke(this, new CPUEventArgs(this)); } - //UT + public void ResetMemory() { _memoryBus.EraseRam(); @@ -391,5 +386,5 @@ private void SetProperties() Cycles = cpu._CpuCycle; } - + } From eca9cd5e2a65c0a8c421b2deeaa084ab4bb04f43 Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Tue, 22 Jul 2025 08:13:27 +0200 Subject: [PATCH 3/9] add comments --- CPU_emu/MemoryBus/RamBus.cs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CPU_emu/MemoryBus/RamBus.cs b/CPU_emu/MemoryBus/RamBus.cs index 6574be4..dc4b3ae 100644 --- a/CPU_emu/MemoryBus/RamBus.cs +++ b/CPU_emu/MemoryBus/RamBus.cs @@ -19,21 +19,43 @@ public RamBus(byte[] memory) { _memory = memory; } + + /// + /// Read data from random address + /// + /// address to read + /// byte public byte Read(ushort address) { return _memory[address]; } + /// + /// Write data to random address + /// + /// Address to store data + /// data public void Write(ushort address, byte value) { _memory[address] = value; } + /// + /// Load a chunk of data into RAM + /// + /// Startaddress + /// data byte[] public void Load(ushort address, params byte[] data) { Array.Copy(data, 0, _memory, address, data.Length); } + /// + /// Reada range of RAM + /// + /// Startaddress + /// Lenght of data + /// byte[] public byte[] Dump(ushort address, int length) { return _memory.Skip(address).Take(length).ToArray(); From 9f580591175745f326954988f6c1935ed16bcf38 Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Tue, 22 Jul 2025 11:09:05 +0200 Subject: [PATCH 4/9] add folder GUI-Helper and move som files --- CPU_emu/GUI-Helper/LedBulb.cs | 157 +++++++++++ CPU_emu/GUI-Helper/SevenSegment.cs | 335 ++++++++++++++++++++++++ CPU_emu/GUI-Helper/SevenSegmentArray.cs | 184 +++++++++++++ 3 files changed, 676 insertions(+) create mode 100644 CPU_emu/GUI-Helper/LedBulb.cs create mode 100644 CPU_emu/GUI-Helper/SevenSegment.cs create mode 100644 CPU_emu/GUI-Helper/SevenSegmentArray.cs diff --git a/CPU_emu/GUI-Helper/LedBulb.cs b/CPU_emu/GUI-Helper/LedBulb.cs new file mode 100644 index 0000000..2503df7 --- /dev/null +++ b/CPU_emu/GUI-Helper/LedBulb.cs @@ -0,0 +1,157 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.Diagnostics; + +namespace Bulb { + + /// + /// The LEDBulb is a .Net control for Windows Forms that emulates an + /// LED light with two states On and Off. The purpose of the control is to + /// provide a sleek looking representation of an LED light that is sizable, + /// has a transparent background and can be set to different colors. + /// + public partial class LedBulb : Control { + + #region Public and Private Members + + private Color _color; + private bool _on = true; + private Color _reflectionColor = Color.FromArgb(180, 255, 255, 255); + private Color[] _surroundColor = new Color[] { Color.FromArgb(0, 255, 255, 255) }; + private Timer _timer = new Timer(); + + /// + /// Gets or Sets the color of the LED light + /// + [DefaultValue(typeof(Color), "153, 255, 54")] + public Color Color { + get { return _color; } + set { + _color = value; + //this.DarkColor = _color; + this.DarkColor = ControlPaint.Dark(_color, 90); + this.DarkDarkColor = ControlPaint.Dark(_color,70); + this.Invalidate(); // Redraw the control + } + } + + /// + /// Dark shade of the LED color used for gradient + /// + public Color DarkColor { get; protected set; } + + /// + /// Very dark shade of the LED color used for gradient + /// + public Color DarkDarkColor { get; protected set; } + + /// + /// Gets or Sets whether the light is turned on + /// + public bool On { + get { return _on; } + set { _on = value; this.Invalidate(); } + } + + #endregion + + #region Constructor + + public LedBulb() { + SetStyle(ControlStyles.DoubleBuffer + | ControlStyles.AllPaintingInWmPaint + | ControlStyles.ResizeRedraw + | ControlStyles.UserPaint + | ControlStyles.SupportsTransparentBackColor, true); + + this.Color = Color.FromArgb(255, 153, 255, 54); + _timer.Tick += new EventHandler( + (object sender, EventArgs e) => { this.On = !this.On; } + ); + } + + #endregion + + #region Methods + + /// + /// Handles the Paint event for this UserControl + /// + protected override void OnPaint(PaintEventArgs e){ + // Create an offscreen graphics object for double buffering + Bitmap offScreenBmp = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height); + using (System.Drawing.Graphics g = Graphics.FromImage(offScreenBmp)) { + g.SmoothingMode = SmoothingMode.HighQuality; + // Draw the control + drawControl(g, this.On); + // Draw the image to the screen + e.Graphics.DrawImageUnscaled(offScreenBmp, 0, 0); + } + } + + /// + /// Renders the control to an image + /// + private void drawControl(Graphics g, bool on) { + // Is the bulb on or off + Color lightColor = (on)? this.Color : Color.FromArgb(150, this.DarkColor); + Color darkColor = (on) ? this.DarkColor : this.DarkDarkColor; + + // Calculate the dimensions of the bulb + int width = this.Width - (this.Padding.Left + this.Padding.Right); + int height = this.Height - (this.Padding.Top + this.Padding.Bottom); + // Diameter is the lesser of width and height + int diameter = Math.Min(width, height); + // Subtract 1 pixel so ellipse doesn't get cut off + diameter = Math.Max(diameter - 1, 1); + + // Draw the background ellipse + var rectangle = new Rectangle(this.Padding.Left, this.Padding.Top, diameter, diameter); + g.FillEllipse(new SolidBrush(darkColor), rectangle); + + // Draw the glow gradient + var path = new GraphicsPath(); + path.AddEllipse(rectangle); + var pathBrush = new PathGradientBrush(path); + pathBrush.CenterColor = lightColor; + pathBrush.SurroundColors = new Color[] { Color.FromArgb(0, lightColor) }; + g.FillEllipse(pathBrush, rectangle); + + // Draw the white reflection gradient + var offset = Convert.ToInt32(diameter * .15F); + var diameter1 = Convert.ToInt32(rectangle.Width * .8F); + var whiteRect = new Rectangle(rectangle.X - offset, rectangle.Y - offset, diameter1, diameter1); + var path1 = new GraphicsPath(); + path1.AddEllipse(whiteRect); + var pathBrush1 = new PathGradientBrush(path); + pathBrush1.CenterColor = _reflectionColor; + pathBrush1.SurroundColors = _surroundColor; + g.FillEllipse(pathBrush1, whiteRect); + + // Draw the border + g.SetClip(this.ClientRectangle); + if (this.On) g.DrawEllipse(new Pen(Color.FromArgb(85, Color.Black),1F), rectangle); + } + + /// + /// Causes the Led to start blinking + /// + /// Number of milliseconds to blink for. 0 stops blinking + public void Blink(int milliseconds) { + if (milliseconds > 0) { + this.On = true; + _timer.Interval = milliseconds; + _timer.Enabled = true; + } + else { + _timer.Enabled = false; + this.On = false; + } + } + + #endregion + } +} diff --git a/CPU_emu/GUI-Helper/SevenSegment.cs b/CPU_emu/GUI-Helper/SevenSegment.cs new file mode 100644 index 0000000..aaa33ac --- /dev/null +++ b/CPU_emu/GUI-Helper/SevenSegment.cs @@ -0,0 +1,335 @@ +using System; +using System.Windows.Forms; +using System.Drawing; +using System.Drawing.Drawing2D; + +/* + * Seven-segment LED control for .NET + * + * Copyright 2009-2019 Dmitry Brant. All Rights Reserved. + * me@dmitrybrant.com + * http://dmitrybrant.com + * + * This component is free for personal use. + * If you would like to use it in a commercial application, please + * e-mail me at the address above. + * This software comes as-is, with no warranty. + * + * Features: + * - Customizable colors + * - Displays numbers and most letters, plus decimal point + * - Supports custom LED patterns + * - Customizable segment width and italics + * + */ + +namespace DmitryBrant.CustomControls +{ + public class SevenSegment : UserControl + { + private Point[][] segPoints; + + private int gridHeight = 80; + private int gridWidth = 48; + private int elementWidth = 10; + private float italicFactor = 0.0F; + private Color colorBackground = Color.DarkGray; + private Color colorDark = Color.DimGray; + private Color colorLight = Color.Red; + + private string theValue = null; + private bool showDot = true, dotOn = false; + private bool showColon = false, colonOn = false; + private int customPattern = 0; + + /// + /// These are the various bit patterns that represent the characters + /// that can be displayed in the seven segments. Bits 0 through 6 + /// correspond to each of the LEDs, from top to bottom! + /// + public enum ValuePattern + { + None = 0x0, Zero = 0x77, One = 0x24, Two = 0x5D, Three = 0x6D, + Four = 0x2E, Five = 0x6B, Six = 0x7B, Seven = 0x25, + Eight = 0x7F, Nine = 0x6F, A = 0x3F, B = 0x7A, C = 0x53, c = 0x58, + D = 0x7C, E = 0x5B, F = 0x1B, G = 0x73, H = 0x3E, h = 0x3A, i = 0x20, + J = 0x74, L = 0x52, N = 0x38, o = 0x78, P = 0x1F, Q = 0x2F, R = 0x18, + T = 0x5A, U = 0x76, u = 0x70, Y = 0x6E, + Dash = 0x8, Equals = 0x48, Degrees = 0xF, + Apostrophe = 0x2, Quote = 0x6, RBracket = 0x65, + Underscore = 0x40, Identical = 0x49, Not = 0x28 + } + + public SevenSegment() + { + SuspendLayout(); + Name = "SevenSegment"; + Size = new Size(32, 64); + Paint += new PaintEventHandler(SevenSegment_Paint); + Resize += new EventHandler(SevenSegment_Resize); + ResumeLayout(false); + + TabStop = false; + Padding = new Padding(4, 4, 4, 4); + DoubleBuffered = true; + + segPoints = new Point[7][]; + for (int i = 0; i < 7; i++) segPoints[i] = new Point[6]; + + RecalculatePoints(); + } + + /// + /// Recalculate the points that represent the polygons of the + /// seven segments, whether we're just initializing or + /// changing the segment width. + /// + private void RecalculatePoints() + { + int halfHeight = gridHeight / 2, halfWidth = elementWidth / 2; + + int p = 0; + segPoints[p][0].X = elementWidth + 1; segPoints[p][0].Y = 0; + segPoints[p][1].X = gridWidth - elementWidth - 1; segPoints[p][1].Y = 0; + segPoints[p][2].X = gridWidth - halfWidth - 1; segPoints[p][2].Y = halfWidth; + segPoints[p][3].X = gridWidth - elementWidth - 1; segPoints[p][3].Y = elementWidth; + segPoints[p][4].X = elementWidth + 1; segPoints[p][4].Y = elementWidth; + segPoints[p][5].X = halfWidth + 1; segPoints[p][5].Y = halfWidth; + + p++; + segPoints[p][0].X = 0; segPoints[p][0].Y = elementWidth + 1; + segPoints[p][1].X = halfWidth; segPoints[p][1].Y = halfWidth + 1; + segPoints[p][2].X = elementWidth; segPoints[p][2].Y = elementWidth + 1; + segPoints[p][3].X = elementWidth; segPoints[p][3].Y = halfHeight - halfWidth - 1; + segPoints[p][4].X = 4; segPoints[p][4].Y = halfHeight - 1; + segPoints[p][5].X = 0; segPoints[p][5].Y = halfHeight - 1; + + p++; + segPoints[p][0].X = gridWidth - elementWidth; segPoints[p][0].Y = elementWidth + 1; + segPoints[p][1].X = gridWidth - halfWidth; segPoints[p][1].Y = halfWidth + 1; + segPoints[p][2].X = gridWidth; segPoints[p][2].Y = elementWidth + 1; + segPoints[p][3].X = gridWidth; segPoints[p][3].Y = halfHeight - 1; + segPoints[p][4].X = gridWidth - 4; segPoints[p][4].Y = halfHeight - 1; + segPoints[p][5].X = gridWidth - elementWidth; segPoints[p][5].Y = halfHeight - halfWidth - 1; + + p++; + segPoints[p][0].X = elementWidth + 1; segPoints[p][0].Y = halfHeight - halfWidth; + segPoints[p][1].X = gridWidth - elementWidth - 1; segPoints[p][1].Y = halfHeight - halfWidth; + segPoints[p][2].X = gridWidth - 5; segPoints[p][2].Y = halfHeight; + segPoints[p][3].X = gridWidth - elementWidth - 1; segPoints[p][3].Y = halfHeight + halfWidth; + segPoints[p][4].X = elementWidth + 1; segPoints[p][4].Y = halfHeight + halfWidth; + segPoints[p][5].X = 5; segPoints[p][5].Y = halfHeight; + + p++; + segPoints[p][0].X = 0; segPoints[p][0].Y = halfHeight + 1; + segPoints[p][1].X = 4; segPoints[p][1].Y = halfHeight + 1; + segPoints[p][2].X = elementWidth; segPoints[p][2].Y = halfHeight + halfWidth + 1; + segPoints[p][3].X = elementWidth; segPoints[p][3].Y = gridHeight - elementWidth - 1; + segPoints[p][4].X = halfWidth; segPoints[p][4].Y = gridHeight - halfWidth - 1; + segPoints[p][5].X = 0; segPoints[p][5].Y = gridHeight - elementWidth - 1; + + p++; + segPoints[p][0].X = gridWidth - elementWidth; segPoints[p][0].Y = halfHeight + halfWidth + 1; + segPoints[p][1].X = gridWidth - 4; segPoints[p][1].Y = halfHeight + 1; + segPoints[p][2].X = gridWidth; segPoints[p][2].Y = halfHeight + 1; + segPoints[p][3].X = gridWidth; segPoints[p][3].Y = gridHeight - elementWidth - 1; + segPoints[p][4].X = gridWidth - halfWidth; segPoints[p][4].Y = gridHeight - halfWidth - 1; + segPoints[p][5].X = gridWidth - elementWidth; segPoints[p][5].Y = gridHeight - elementWidth - 1; + + p++; + segPoints[p][0].X = elementWidth + 1; segPoints[p][0].Y = gridHeight - elementWidth; + segPoints[p][1].X = gridWidth - elementWidth - 1; segPoints[p][1].Y = gridHeight - elementWidth; + segPoints[p][2].X = gridWidth - halfWidth - 1; segPoints[p][2].Y = gridHeight - halfWidth; + segPoints[p][3].X = gridWidth - elementWidth - 1; segPoints[p][3].Y = gridHeight; + segPoints[p][4].X = elementWidth + 1; segPoints[p][4].Y = gridHeight; + segPoints[p][5].X = halfWidth + 1; segPoints[p][5].Y = gridHeight - halfWidth; + } + + /// + /// Background color of the 7-segment display. + /// + public Color ColorBackground { get { return colorBackground; } set { colorBackground = value; Invalidate(); } } + /// + /// Color of inactive LED segments. + /// + public Color ColorDark { get { return colorDark; } set { colorDark = value; Invalidate(); } } + /// + /// Color of active LED segments. + /// + public Color ColorLight { get { return colorLight; } set { colorLight = value; Invalidate(); } } + + /// + /// Width of LED segments. + /// + public int ElementWidth { get { return elementWidth; } set { elementWidth = value; RecalculatePoints(); Invalidate(); } } + /// + /// Shear coefficient for italicizing the displays. Try a value like -0.1. + /// + public float ItalicFactor { get { return italicFactor; } set { italicFactor = value; Invalidate(); } } + + private void SevenSegment_Resize(object sender, EventArgs e) { Invalidate(); } + protected override void OnPaddingChanged(EventArgs e) { base.OnPaddingChanged(e); Invalidate(); } + + protected override void OnPaintBackground(PaintEventArgs e) + { + //base.OnPaintBackground(e); + e.Graphics.Clear(colorBackground); + } + + /// + /// Character to be displayed on the seven segments. Supported characters + /// are digits and most letters. + /// + public string Value + { + get { return theValue; } + set + { + customPattern = 0; + theValue = value; + Invalidate(); + if (value == null || value.Length == 0) + { + return; + } + //is it an integer? + int tempValue; + if (int.TryParse(value, out tempValue)) + { + if (tempValue > 9) tempValue = 9; if (tempValue < 0) tempValue = 0; + switch (tempValue) + { + case 0: customPattern = (int)ValuePattern.Zero; break; + case 1: customPattern = (int)ValuePattern.One; break; + case 2: customPattern = (int)ValuePattern.Two; break; + case 3: customPattern = (int)ValuePattern.Three; break; + case 4: customPattern = (int)ValuePattern.Four; break; + case 5: customPattern = (int)ValuePattern.Five; break; + case 6: customPattern = (int)ValuePattern.Six; break; + case 7: customPattern = (int)ValuePattern.Seven; break; + case 8: customPattern = (int)ValuePattern.Eight; break; + case 9: customPattern = (int)ValuePattern.Nine; break; + } + } + else + { + //is it a letter? + switch (value[0]) + { + case 'A': case 'a': customPattern = (int)ValuePattern.A; break; + case 'B': case 'b': customPattern = (int)ValuePattern.B; break; + case 'C': customPattern = (int)ValuePattern.C; break; + case 'c': customPattern = (int)ValuePattern.c; break; + case 'D': case 'd': customPattern = (int)ValuePattern.D; break; + case 'E': case 'e': customPattern = (int)ValuePattern.E; break; + case 'F': case 'f': customPattern = (int)ValuePattern.F; break; + case 'G': case 'g': customPattern = (int)ValuePattern.G; break; + case 'H': customPattern = (int)ValuePattern.H; break; + case 'h': customPattern = (int)ValuePattern.h; break; + case 'I': customPattern = (int)ValuePattern.One; break; + case 'i': customPattern = (int)ValuePattern.i; break; + case 'J': case 'j': customPattern = (int)ValuePattern.J; break; + case 'L': case 'l': customPattern = (int)ValuePattern.L; break; + case 'N': case 'n': customPattern = (int)ValuePattern.N; break; + case 'O': customPattern = (int)ValuePattern.Zero; break; + case 'o': customPattern = (int)ValuePattern.o; break; + case 'P': case 'p': customPattern = (int)ValuePattern.P; break; + case 'Q': case 'q': customPattern = (int)ValuePattern.Q; break; + case 'R': case 'r': customPattern = (int)ValuePattern.R; break; + case 'S': case 's': customPattern = (int)ValuePattern.Five; break; + case 'T': case 't': customPattern = (int)ValuePattern.T; break; + case 'U': customPattern = (int)ValuePattern.U; break; + case 'u': case 'µ': case 'μ': customPattern = (int)ValuePattern.u; break; + case 'Y': case 'y': customPattern = (int)ValuePattern.Y; break; + case '-': customPattern = (int)ValuePattern.Dash; break; + case '=': customPattern = (int)ValuePattern.Equals; break; + case '°': customPattern = (int)ValuePattern.Degrees; break; + case '\'': customPattern = (int)ValuePattern.Apostrophe; break; + case '"': customPattern = (int)ValuePattern.Quote; break; + case '[': case '{': customPattern = (int)ValuePattern.C; break; + case ']': case '}': customPattern = (int)ValuePattern.RBracket; break; + case '_': customPattern = (int)ValuePattern.Underscore; break; + case '≡': customPattern = (int)ValuePattern.Identical; break; + case '¬': customPattern = (int)ValuePattern.Not; break; + } + } + } + } + + /// + /// Set a custom bit pattern to be displayed on the seven segments. This is an + /// integer value where bits 0 through 6 correspond to each respective LED + /// segment. + /// + public int CustomPattern { get { return customPattern; } set { customPattern = value; Invalidate(); } } + + /// + /// Specifies if the decimal point LED is displayed. + /// + public bool DecimalShow { get { return showDot; } set { showDot = value; Invalidate(); } } + /// + /// Specifies if the decimal point LED is active. + /// + public bool DecimalOn { get { return dotOn; } set { dotOn = value; Invalidate(); } } + + /// + /// Specifies if the colon LEDs are displayed. + /// + public bool ColonShow { get { return showColon; } set { showColon = value; Invalidate(); } } + /// + /// Specifies if the colon LEDs are active. + /// + public bool ColonOn { get { return colonOn; } set { colonOn = value; Invalidate(); } } + + private void SevenSegment_Paint(object sender, PaintEventArgs e) + { + int useValue = customPattern; + + Brush brushLight = new SolidBrush(colorLight); + Brush brushDark = new SolidBrush(colorDark); + + // Define transformation for our container... + RectangleF srcRect; + + int colonWidth = gridWidth / 4; + + if(showColon){ + srcRect = new RectangleF(0.0F, 0.0F, gridWidth + colonWidth, gridHeight); + }else{ + srcRect = new RectangleF(0.0F, 0.0F, gridWidth, gridHeight); + } + RectangleF destRect = new RectangleF(Padding.Left, Padding.Top, Width - Padding.Left - Padding.Right, Height - Padding.Top - Padding.Bottom); + + // Begin graphics container that remaps coordinates for our convenience + GraphicsContainer containerState = e.Graphics.BeginContainer(destRect, srcRect, GraphicsUnit.Pixel); + + Matrix trans = new Matrix(); + trans.Shear(italicFactor, 0.0F); + e.Graphics.Transform = trans; + + e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + e.Graphics.PixelOffsetMode = PixelOffsetMode.Default; + + // Draw elements based on whether the corresponding bit is high + e.Graphics.FillPolygon((useValue & 0x1) == 0x1 ? brushLight : brushDark, segPoints[0]); + e.Graphics.FillPolygon((useValue & 0x2) == 0x2 ? brushLight : brushDark, segPoints[1]); + e.Graphics.FillPolygon((useValue & 0x4) == 0x4 ? brushLight : brushDark, segPoints[2]); + e.Graphics.FillPolygon((useValue & 0x8) == 0x8 ? brushLight : brushDark, segPoints[3]); + e.Graphics.FillPolygon((useValue & 0x10) == 0x10 ? brushLight : brushDark, segPoints[4]); + e.Graphics.FillPolygon((useValue & 0x20) == 0x20 ? brushLight : brushDark, segPoints[5]); + e.Graphics.FillPolygon((useValue & 0x40) == 0x40 ? brushLight : brushDark, segPoints[6]); + + if (showDot) + e.Graphics.FillEllipse(dotOn ? brushLight : brushDark, gridWidth - 1, gridHeight - elementWidth + 1, elementWidth, elementWidth); + + if (showColon) + { + e.Graphics.FillEllipse(colonOn ? brushLight : brushDark, gridWidth + colonWidth - 4, gridHeight / 4 - elementWidth + 8, elementWidth, elementWidth); + e.Graphics.FillEllipse(colonOn ? brushLight : brushDark, gridWidth + colonWidth - 4, gridHeight * 3 / 4 - elementWidth + 4, elementWidth, elementWidth); + } + + e.Graphics.EndContainer(containerState); + } + + } +} diff --git a/CPU_emu/GUI-Helper/SevenSegmentArray.cs b/CPU_emu/GUI-Helper/SevenSegmentArray.cs new file mode 100644 index 0000000..41f74c4 --- /dev/null +++ b/CPU_emu/GUI-Helper/SevenSegmentArray.cs @@ -0,0 +1,184 @@ +using System; +using System.Windows.Forms; +using System.Drawing; + +/* + * Seven-segment LED array control for .NET + * (uses the original seven-segment LED control) + * + * Copyright 2009-2019 Dmitry Brant. All Rights Reserved. + * me@dmitrybrant.com + * http://dmitrybrant.com + * + * This component is free for personal use. + * If you would like to use it in a commercial application, please + * e-mail me at the address above. + * This software comes as-is, with no warranty. + * + * Features: + * - Arbitrary number of array elements + * - All the customizable settings of the original 7-seg control + * - Accepts a string as a value, and distributes the characters + * among the array elements, automatically handling decimal points. + * + */ + +namespace DmitryBrant.CustomControls +{ + public class SevenSegmentArray : UserControl + { + /// + /// Array of segment controls that are currently children of this control. + /// + private SevenSegment[] segments = null; + + private int elementWidth = 10; + private float italicFactor = 0.0F; + private Color colorBackground = Color.DarkGray; + private Color colorDark = Color.DimGray; + private Color colorLight = Color.Red; + private bool showDot = true; + private Padding elementPadding; + + private string theValue = null; + + public SevenSegmentArray() + { + SuspendLayout(); + Name = "SevenSegmentArray"; + Size = new Size(100, 25); + Resize += new EventHandler(SevenSegmentArray_Resize); + ResumeLayout(false); + + TabStop = false; + elementPadding = new Padding(4, 4, 4, 4); + RecreateSegments(4); + } + + /// + /// Change the number of elements in our LED array. This destroys + /// the previous elements, and creates new ones in their place, applying + /// all the current options to the new ones. + /// + /// Number of elements to create. + private void RecreateSegments(int count) + { + if (segments != null) + for (int i = 0; i < segments.Length; i++) { segments[i].Parent = null; segments[i].Dispose(); } + + if (count <= 0) return; + segments = new SevenSegment[count]; + + for (int i = 0; i < count; i++) + { + segments[i] = new SevenSegment(); + segments[i].Parent = this; + segments[i].Top = 0; + segments[i].Height = Height; + segments[i].Anchor = AnchorStyles.Top | AnchorStyles.Bottom; + segments[i].Visible = true; + } + + ResizeSegments(); + UpdateSegments(); + Value = theValue; + } + + /// + /// Align the elements of the array to fit neatly within the + /// width of the parent control. + /// + private void ResizeSegments() + { + int segWidth = Width / segments.Length; + for (int i = 0; i < segments.Length; i++) + { + segments[i].Left = Width * (segments.Length - 1 - i) / segments.Length; + segments[i].Width = segWidth; + } + } + + /// + /// Update the properties of each element with the properties + /// we have stored. + /// + private void UpdateSegments() + { + for (int i = 0; i < segments.Length; i++) + { + segments[i].ColorBackground = colorBackground; + segments[i].ColorDark = colorDark; + segments[i].ColorLight = colorLight; + segments[i].ElementWidth = elementWidth; + segments[i].ItalicFactor = italicFactor; + segments[i].DecimalShow = showDot; + segments[i].Padding = elementPadding; + } + } + + private void SevenSegmentArray_Resize(object sender, EventArgs e) { ResizeSegments(); } + + protected override void OnPaintBackground(PaintEventArgs e) { e.Graphics.Clear(colorBackground); } + + /// + /// Background color of the LED array. + /// + public Color ColorBackground { get { return colorBackground; } set { colorBackground = value; UpdateSegments(); } } + /// + /// Color of inactive LED segments. + /// + public Color ColorDark { get { return colorDark; } set { colorDark = value; UpdateSegments(); } } + /// + /// Color of active LED segments. + /// + public Color ColorLight { get { return colorLight; } set { colorLight = value; UpdateSegments(); } } + + /// + /// Width of LED segments. + /// + public int ElementWidth { get { return elementWidth; } set { elementWidth = value; UpdateSegments(); } } + /// + /// Shear coefficient for italicizing the displays. Try a value like -0.1. + /// + public float ItalicFactor { get { return italicFactor; } set { italicFactor = value; UpdateSegments(); } } + /// + /// Specifies if the decimal point LED is displayed. + /// + public bool DecimalShow { get { return showDot; } set { showDot = value; UpdateSegments(); } } + + /// + /// Number of seven-segment elements in this array. + /// + public int ArrayCount { get { return segments.Length; } set { if ((value > 0) && (value <= 100)) RecreateSegments(value); } } + /// + /// Padding that applies to each seven-segment element in the array. + /// Tweak these numbers to get the perfect appearance for the array of your size. + /// + public Padding ElementPadding { get { return elementPadding; } set { elementPadding = value; UpdateSegments(); } } + + /// + /// The value to be displayed on the LED array. This can contain numbers, + /// certain letters, and decimal points. + /// + public string Value + { + get { return theValue; } + set + { + theValue = value; + for (int i = 0; i < segments.Length; i++) { segments[i].CustomPattern = 0; segments[i].DecimalOn = false; } + if (theValue != null) + { + int segmentIndex = 0; + for (int i = theValue.Length - 1; i >= 0; i--) + { + if (segmentIndex >= segments.Length) break; + if (theValue[i] == '.') segments[segmentIndex].DecimalOn = true; + else segments[segmentIndex++].Value = theValue[i].ToString(); + } + } + } + } + + } +} From 3a5c1dcab04773eb070be3494fd1fca8efd05fae Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Tue, 22 Jul 2025 11:10:53 +0200 Subject: [PATCH 5/9] add folder CPU add addressing helper methods rename CPU_CMD_Methods.cs --- CPU_emu/{Class_CPU.cs => CPU/CPU.cs} | 7 +- .../CPU_CMD_Methods.cs} | 81 ++++- CPU_emu/CPU/CPU_addressing_helper.cs | 74 ++++ CPU_emu/CPU_emu.opcodes.cs | 37 -- CPU_emu/LedBulb.cs | 157 -------- CPU_emu/SevenSegment.cs | 335 ------------------ CPU_emu/SevenSegmentArray.cs | 184 ---------- 7 files changed, 145 insertions(+), 730 deletions(-) rename CPU_emu/{Class_CPU.cs => CPU/CPU.cs} (98%) rename CPU_emu/{CPU_emu.CMD_Methods.cs => CPU/CPU_CMD_Methods.cs} (52%) create mode 100644 CPU_emu/CPU/CPU_addressing_helper.cs delete mode 100644 CPU_emu/CPU_emu.opcodes.cs delete mode 100644 CPU_emu/LedBulb.cs delete mode 100644 CPU_emu/SevenSegment.cs delete mode 100644 CPU_emu/SevenSegmentArray.cs diff --git a/CPU_emu/Class_CPU.cs b/CPU_emu/CPU/CPU.cs similarity index 98% rename from CPU_emu/Class_CPU.cs rename to CPU_emu/CPU/CPU.cs index ba469e0..d91f811 100644 --- a/CPU_emu/Class_CPU.cs +++ b/CPU_emu/CPU/CPU.cs @@ -186,11 +186,6 @@ private void CallInstruction(Type thisType, byte instruction) } } - private uint AddrAbsolute() - { - return FetchWord(ref _CpuCycle); - } - private byte PullByteFromStack(ref ulong CpuCycle) { IncrementSP(); @@ -230,7 +225,7 @@ private byte FetchByte() return data; } - private ushort FetchWord(ref ulong CpuCycle) + private ushort FetchWord() { ushort LoByte = ReadByteFromMemory((ushort)PC); PC++; diff --git a/CPU_emu/CPU_emu.CMD_Methods.cs b/CPU_emu/CPU/CPU_CMD_Methods.cs similarity index 52% rename from CPU_emu/CPU_emu.CMD_Methods.cs rename to CPU_emu/CPU/CPU_CMD_Methods.cs index d70669a..a6153f4 100644 --- a/CPU_emu/CPU_emu.CMD_Methods.cs +++ b/CPU_emu/CPU/CPU_CMD_Methods.cs @@ -15,29 +15,85 @@ public void Cmd_00() #endregion #region LDA - // Load Accumulator immidiate A9 + [Opcode(2)] - public void Cmd_A9() + public void Cmd_A9() // Load Accumulator immidiate A9 { - SetRegister("A", FetchByte()); + byte value = AddrImmediate(); + SetRegister("A", value); SetZeroAndNegativeFlags(A); } - // Load Accumulator zeropage A5 - public void Cmd_A5() + // LDA $zz + [Opcode(2)] + public void Cmd_A5() // Load Accumulator zeropage A5 { - SetRegister("A", ReadByteFromMemory(FetchByte())); + ushort addr = AddrZeroPage(); + byte value = ReadByteFromMemory(addr); + SetRegister("A", value); SetZeroAndNegativeFlags(A); } - // Load Accumulator zeropage X B5 - public void Cmd_B5() + // LDA $zz,X + [Opcode(2)] + public void Cmd_B5() // Load Accumulator zeropage X B5 { - byte b_tmp = FetchByte(); - b_tmp += X; // add regX to address - SetRegister("A", ReadByteFromMemory(b_tmp)); + ushort addr = AddrZeroPageX(); + byte value = ReadByteFromMemory(addr); + SetRegister("A", value); + SetZeroAndNegativeFlags(A); + } + + // LDA $nnnn (absolute) + [Opcode(3)] + public void Cmd_AD() + { + ushort addr = AddrAbsolute(); + byte value = ReadByteFromMemory(addr); + SetRegister("A", value); SetZeroAndNegativeFlags(A); } + + // LDA $nnnn,X + [Opcode(3)] + public void Cmd_BD() + { + ushort addr = AddrAbsoluteX(); + byte value = ReadByteFromMemory(addr); + SetRegister("A", value); + SetZeroAndNegativeFlags(A); + } + + // LDA $nnnn,Y + [Opcode(3)] + public void Cmd_B9() + { + ushort addr = AddrAbsoluteY(); + byte value = ReadByteFromMemory(addr); + SetRegister("A", value); + SetZeroAndNegativeFlags(A); + } + + // LDA ($zz,X) – Indirect,X + [Opcode(2)] + public void Cmd_A1() + { + ushort addr = AddrIndirectX(); + byte value = ReadByteFromMemory(addr); + SetRegister("A", value); + SetZeroAndNegativeFlags(A); + } + + // LDA ($zz),Y – Indirect,Y + [Opcode(2)] + public void Cmd_B1() + { + ushort addr = AddrIndirectY(); + byte value = ReadByteFromMemory(addr); + SetRegister("A", value); + SetZeroAndNegativeFlags(A); + } + #endregion #region LDX @@ -105,4 +161,7 @@ public void Cmd_48() } #endregion + + + } \ No newline at end of file diff --git a/CPU_emu/CPU/CPU_addressing_helper.cs b/CPU_emu/CPU/CPU_addressing_helper.cs new file mode 100644 index 0000000..ddc9c61 --- /dev/null +++ b/CPU_emu/CPU/CPU_addressing_helper.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CPU_emulator +{ + public partial class CPU + { + #region addressig helper + + // #Immediate + private byte AddrImmediate() + { + return FetchByte(); + } + + // $zz – Zero Page + private ushort AddrZeroPage() + { + // return (ushort)(addr & 0x00FF); cast ushort + return FetchByte(); // implicit ushort + } + + // Zero Page,X – 8-Bit-Baseaddress + X, Wrap at 0xFF → 0x00 + private ushort AddrZeroPageX() + { + byte baseAddr = FetchByte(); + byte effectiveAddr = (byte)(baseAddr + X); // automatic 8-Bit-Wrap + return effectiveAddr; + } + + // Absolute + private ushort AddrAbsolute() + { + return FetchWord(); + } + + // Absolute,X (no page wrap taken into account) + private ushort AddrAbsoluteX() + { + return (ushort)(AddrAbsolute() + X); + } + + // Absolute,Y + private ushort AddrAbsoluteY() + { + return (ushort)(AddrAbsolute() + Y); + } + + // Indirect,X = ($zz,X) + private ushort AddrIndirectX() + { + byte zpAddr = (byte)(FetchByte() + X); + byte lo = ReadByteFromMemory(zpAddr); + byte hi = ReadByteFromMemory((byte)(zpAddr + 1)); + return (ushort)(lo | (hi << 8)); + } + + // Indirect,Y = ($zz),Y + private ushort AddrIndirectY() + { + byte zpAddr = FetchByte(); + byte lo = ReadByteFromMemory(zpAddr); + byte hi = ReadByteFromMemory((byte)(zpAddr + 1)); + return (ushort)((lo | (hi << 8)) + Y); + } + + + + #endregion + } +} diff --git a/CPU_emu/CPU_emu.opcodes.cs b/CPU_emu/CPU_emu.opcodes.cs deleted file mode 100644 index c1f7b6d..0000000 --- a/CPU_emu/CPU_emu.opcodes.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CPU_emulator -{ - public partial class CPU - { - //private const byte - // OC_BRK = 0x00, - // // LDA - // OC_LDA_IM = 0xA9, - // OC_LDA_ZP = 0xA5, - // OC_LDA_ZPX = 0xB5, - // // LDX - // OC_LDX_IM = 0xA2, - // OC_LDX_ZP = 0xA6, - // OC_LDX_ZPY = 0xB6, - // // LDY - // OC_LDY_IM = 0xA0, - // OC_LDY_ZP = 0xA4, - // OC_LDY_ZPX = 0xB4, - - // // JMP - // OC_JMP_ABS = 0x4C, - // OC_JMP_IND = 0x6C, - - // // Stack - // OC_PHA = 0x48, - // OC_PLA = 0x68 - // ; - - - } -} diff --git a/CPU_emu/LedBulb.cs b/CPU_emu/LedBulb.cs deleted file mode 100644 index 2503df7..0000000 --- a/CPU_emu/LedBulb.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using System.Diagnostics; - -namespace Bulb { - - /// - /// The LEDBulb is a .Net control for Windows Forms that emulates an - /// LED light with two states On and Off. The purpose of the control is to - /// provide a sleek looking representation of an LED light that is sizable, - /// has a transparent background and can be set to different colors. - /// - public partial class LedBulb : Control { - - #region Public and Private Members - - private Color _color; - private bool _on = true; - private Color _reflectionColor = Color.FromArgb(180, 255, 255, 255); - private Color[] _surroundColor = new Color[] { Color.FromArgb(0, 255, 255, 255) }; - private Timer _timer = new Timer(); - - /// - /// Gets or Sets the color of the LED light - /// - [DefaultValue(typeof(Color), "153, 255, 54")] - public Color Color { - get { return _color; } - set { - _color = value; - //this.DarkColor = _color; - this.DarkColor = ControlPaint.Dark(_color, 90); - this.DarkDarkColor = ControlPaint.Dark(_color,70); - this.Invalidate(); // Redraw the control - } - } - - /// - /// Dark shade of the LED color used for gradient - /// - public Color DarkColor { get; protected set; } - - /// - /// Very dark shade of the LED color used for gradient - /// - public Color DarkDarkColor { get; protected set; } - - /// - /// Gets or Sets whether the light is turned on - /// - public bool On { - get { return _on; } - set { _on = value; this.Invalidate(); } - } - - #endregion - - #region Constructor - - public LedBulb() { - SetStyle(ControlStyles.DoubleBuffer - | ControlStyles.AllPaintingInWmPaint - | ControlStyles.ResizeRedraw - | ControlStyles.UserPaint - | ControlStyles.SupportsTransparentBackColor, true); - - this.Color = Color.FromArgb(255, 153, 255, 54); - _timer.Tick += new EventHandler( - (object sender, EventArgs e) => { this.On = !this.On; } - ); - } - - #endregion - - #region Methods - - /// - /// Handles the Paint event for this UserControl - /// - protected override void OnPaint(PaintEventArgs e){ - // Create an offscreen graphics object for double buffering - Bitmap offScreenBmp = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height); - using (System.Drawing.Graphics g = Graphics.FromImage(offScreenBmp)) { - g.SmoothingMode = SmoothingMode.HighQuality; - // Draw the control - drawControl(g, this.On); - // Draw the image to the screen - e.Graphics.DrawImageUnscaled(offScreenBmp, 0, 0); - } - } - - /// - /// Renders the control to an image - /// - private void drawControl(Graphics g, bool on) { - // Is the bulb on or off - Color lightColor = (on)? this.Color : Color.FromArgb(150, this.DarkColor); - Color darkColor = (on) ? this.DarkColor : this.DarkDarkColor; - - // Calculate the dimensions of the bulb - int width = this.Width - (this.Padding.Left + this.Padding.Right); - int height = this.Height - (this.Padding.Top + this.Padding.Bottom); - // Diameter is the lesser of width and height - int diameter = Math.Min(width, height); - // Subtract 1 pixel so ellipse doesn't get cut off - diameter = Math.Max(diameter - 1, 1); - - // Draw the background ellipse - var rectangle = new Rectangle(this.Padding.Left, this.Padding.Top, diameter, diameter); - g.FillEllipse(new SolidBrush(darkColor), rectangle); - - // Draw the glow gradient - var path = new GraphicsPath(); - path.AddEllipse(rectangle); - var pathBrush = new PathGradientBrush(path); - pathBrush.CenterColor = lightColor; - pathBrush.SurroundColors = new Color[] { Color.FromArgb(0, lightColor) }; - g.FillEllipse(pathBrush, rectangle); - - // Draw the white reflection gradient - var offset = Convert.ToInt32(diameter * .15F); - var diameter1 = Convert.ToInt32(rectangle.Width * .8F); - var whiteRect = new Rectangle(rectangle.X - offset, rectangle.Y - offset, diameter1, diameter1); - var path1 = new GraphicsPath(); - path1.AddEllipse(whiteRect); - var pathBrush1 = new PathGradientBrush(path); - pathBrush1.CenterColor = _reflectionColor; - pathBrush1.SurroundColors = _surroundColor; - g.FillEllipse(pathBrush1, whiteRect); - - // Draw the border - g.SetClip(this.ClientRectangle); - if (this.On) g.DrawEllipse(new Pen(Color.FromArgb(85, Color.Black),1F), rectangle); - } - - /// - /// Causes the Led to start blinking - /// - /// Number of milliseconds to blink for. 0 stops blinking - public void Blink(int milliseconds) { - if (milliseconds > 0) { - this.On = true; - _timer.Interval = milliseconds; - _timer.Enabled = true; - } - else { - _timer.Enabled = false; - this.On = false; - } - } - - #endregion - } -} diff --git a/CPU_emu/SevenSegment.cs b/CPU_emu/SevenSegment.cs deleted file mode 100644 index aaa33ac..0000000 --- a/CPU_emu/SevenSegment.cs +++ /dev/null @@ -1,335 +0,0 @@ -using System; -using System.Windows.Forms; -using System.Drawing; -using System.Drawing.Drawing2D; - -/* - * Seven-segment LED control for .NET - * - * Copyright 2009-2019 Dmitry Brant. All Rights Reserved. - * me@dmitrybrant.com - * http://dmitrybrant.com - * - * This component is free for personal use. - * If you would like to use it in a commercial application, please - * e-mail me at the address above. - * This software comes as-is, with no warranty. - * - * Features: - * - Customizable colors - * - Displays numbers and most letters, plus decimal point - * - Supports custom LED patterns - * - Customizable segment width and italics - * - */ - -namespace DmitryBrant.CustomControls -{ - public class SevenSegment : UserControl - { - private Point[][] segPoints; - - private int gridHeight = 80; - private int gridWidth = 48; - private int elementWidth = 10; - private float italicFactor = 0.0F; - private Color colorBackground = Color.DarkGray; - private Color colorDark = Color.DimGray; - private Color colorLight = Color.Red; - - private string theValue = null; - private bool showDot = true, dotOn = false; - private bool showColon = false, colonOn = false; - private int customPattern = 0; - - /// - /// These are the various bit patterns that represent the characters - /// that can be displayed in the seven segments. Bits 0 through 6 - /// correspond to each of the LEDs, from top to bottom! - /// - public enum ValuePattern - { - None = 0x0, Zero = 0x77, One = 0x24, Two = 0x5D, Three = 0x6D, - Four = 0x2E, Five = 0x6B, Six = 0x7B, Seven = 0x25, - Eight = 0x7F, Nine = 0x6F, A = 0x3F, B = 0x7A, C = 0x53, c = 0x58, - D = 0x7C, E = 0x5B, F = 0x1B, G = 0x73, H = 0x3E, h = 0x3A, i = 0x20, - J = 0x74, L = 0x52, N = 0x38, o = 0x78, P = 0x1F, Q = 0x2F, R = 0x18, - T = 0x5A, U = 0x76, u = 0x70, Y = 0x6E, - Dash = 0x8, Equals = 0x48, Degrees = 0xF, - Apostrophe = 0x2, Quote = 0x6, RBracket = 0x65, - Underscore = 0x40, Identical = 0x49, Not = 0x28 - } - - public SevenSegment() - { - SuspendLayout(); - Name = "SevenSegment"; - Size = new Size(32, 64); - Paint += new PaintEventHandler(SevenSegment_Paint); - Resize += new EventHandler(SevenSegment_Resize); - ResumeLayout(false); - - TabStop = false; - Padding = new Padding(4, 4, 4, 4); - DoubleBuffered = true; - - segPoints = new Point[7][]; - for (int i = 0; i < 7; i++) segPoints[i] = new Point[6]; - - RecalculatePoints(); - } - - /// - /// Recalculate the points that represent the polygons of the - /// seven segments, whether we're just initializing or - /// changing the segment width. - /// - private void RecalculatePoints() - { - int halfHeight = gridHeight / 2, halfWidth = elementWidth / 2; - - int p = 0; - segPoints[p][0].X = elementWidth + 1; segPoints[p][0].Y = 0; - segPoints[p][1].X = gridWidth - elementWidth - 1; segPoints[p][1].Y = 0; - segPoints[p][2].X = gridWidth - halfWidth - 1; segPoints[p][2].Y = halfWidth; - segPoints[p][3].X = gridWidth - elementWidth - 1; segPoints[p][3].Y = elementWidth; - segPoints[p][4].X = elementWidth + 1; segPoints[p][4].Y = elementWidth; - segPoints[p][5].X = halfWidth + 1; segPoints[p][5].Y = halfWidth; - - p++; - segPoints[p][0].X = 0; segPoints[p][0].Y = elementWidth + 1; - segPoints[p][1].X = halfWidth; segPoints[p][1].Y = halfWidth + 1; - segPoints[p][2].X = elementWidth; segPoints[p][2].Y = elementWidth + 1; - segPoints[p][3].X = elementWidth; segPoints[p][3].Y = halfHeight - halfWidth - 1; - segPoints[p][4].X = 4; segPoints[p][4].Y = halfHeight - 1; - segPoints[p][5].X = 0; segPoints[p][5].Y = halfHeight - 1; - - p++; - segPoints[p][0].X = gridWidth - elementWidth; segPoints[p][0].Y = elementWidth + 1; - segPoints[p][1].X = gridWidth - halfWidth; segPoints[p][1].Y = halfWidth + 1; - segPoints[p][2].X = gridWidth; segPoints[p][2].Y = elementWidth + 1; - segPoints[p][3].X = gridWidth; segPoints[p][3].Y = halfHeight - 1; - segPoints[p][4].X = gridWidth - 4; segPoints[p][4].Y = halfHeight - 1; - segPoints[p][5].X = gridWidth - elementWidth; segPoints[p][5].Y = halfHeight - halfWidth - 1; - - p++; - segPoints[p][0].X = elementWidth + 1; segPoints[p][0].Y = halfHeight - halfWidth; - segPoints[p][1].X = gridWidth - elementWidth - 1; segPoints[p][1].Y = halfHeight - halfWidth; - segPoints[p][2].X = gridWidth - 5; segPoints[p][2].Y = halfHeight; - segPoints[p][3].X = gridWidth - elementWidth - 1; segPoints[p][3].Y = halfHeight + halfWidth; - segPoints[p][4].X = elementWidth + 1; segPoints[p][4].Y = halfHeight + halfWidth; - segPoints[p][5].X = 5; segPoints[p][5].Y = halfHeight; - - p++; - segPoints[p][0].X = 0; segPoints[p][0].Y = halfHeight + 1; - segPoints[p][1].X = 4; segPoints[p][1].Y = halfHeight + 1; - segPoints[p][2].X = elementWidth; segPoints[p][2].Y = halfHeight + halfWidth + 1; - segPoints[p][3].X = elementWidth; segPoints[p][3].Y = gridHeight - elementWidth - 1; - segPoints[p][4].X = halfWidth; segPoints[p][4].Y = gridHeight - halfWidth - 1; - segPoints[p][5].X = 0; segPoints[p][5].Y = gridHeight - elementWidth - 1; - - p++; - segPoints[p][0].X = gridWidth - elementWidth; segPoints[p][0].Y = halfHeight + halfWidth + 1; - segPoints[p][1].X = gridWidth - 4; segPoints[p][1].Y = halfHeight + 1; - segPoints[p][2].X = gridWidth; segPoints[p][2].Y = halfHeight + 1; - segPoints[p][3].X = gridWidth; segPoints[p][3].Y = gridHeight - elementWidth - 1; - segPoints[p][4].X = gridWidth - halfWidth; segPoints[p][4].Y = gridHeight - halfWidth - 1; - segPoints[p][5].X = gridWidth - elementWidth; segPoints[p][5].Y = gridHeight - elementWidth - 1; - - p++; - segPoints[p][0].X = elementWidth + 1; segPoints[p][0].Y = gridHeight - elementWidth; - segPoints[p][1].X = gridWidth - elementWidth - 1; segPoints[p][1].Y = gridHeight - elementWidth; - segPoints[p][2].X = gridWidth - halfWidth - 1; segPoints[p][2].Y = gridHeight - halfWidth; - segPoints[p][3].X = gridWidth - elementWidth - 1; segPoints[p][3].Y = gridHeight; - segPoints[p][4].X = elementWidth + 1; segPoints[p][4].Y = gridHeight; - segPoints[p][5].X = halfWidth + 1; segPoints[p][5].Y = gridHeight - halfWidth; - } - - /// - /// Background color of the 7-segment display. - /// - public Color ColorBackground { get { return colorBackground; } set { colorBackground = value; Invalidate(); } } - /// - /// Color of inactive LED segments. - /// - public Color ColorDark { get { return colorDark; } set { colorDark = value; Invalidate(); } } - /// - /// Color of active LED segments. - /// - public Color ColorLight { get { return colorLight; } set { colorLight = value; Invalidate(); } } - - /// - /// Width of LED segments. - /// - public int ElementWidth { get { return elementWidth; } set { elementWidth = value; RecalculatePoints(); Invalidate(); } } - /// - /// Shear coefficient for italicizing the displays. Try a value like -0.1. - /// - public float ItalicFactor { get { return italicFactor; } set { italicFactor = value; Invalidate(); } } - - private void SevenSegment_Resize(object sender, EventArgs e) { Invalidate(); } - protected override void OnPaddingChanged(EventArgs e) { base.OnPaddingChanged(e); Invalidate(); } - - protected override void OnPaintBackground(PaintEventArgs e) - { - //base.OnPaintBackground(e); - e.Graphics.Clear(colorBackground); - } - - /// - /// Character to be displayed on the seven segments. Supported characters - /// are digits and most letters. - /// - public string Value - { - get { return theValue; } - set - { - customPattern = 0; - theValue = value; - Invalidate(); - if (value == null || value.Length == 0) - { - return; - } - //is it an integer? - int tempValue; - if (int.TryParse(value, out tempValue)) - { - if (tempValue > 9) tempValue = 9; if (tempValue < 0) tempValue = 0; - switch (tempValue) - { - case 0: customPattern = (int)ValuePattern.Zero; break; - case 1: customPattern = (int)ValuePattern.One; break; - case 2: customPattern = (int)ValuePattern.Two; break; - case 3: customPattern = (int)ValuePattern.Three; break; - case 4: customPattern = (int)ValuePattern.Four; break; - case 5: customPattern = (int)ValuePattern.Five; break; - case 6: customPattern = (int)ValuePattern.Six; break; - case 7: customPattern = (int)ValuePattern.Seven; break; - case 8: customPattern = (int)ValuePattern.Eight; break; - case 9: customPattern = (int)ValuePattern.Nine; break; - } - } - else - { - //is it a letter? - switch (value[0]) - { - case 'A': case 'a': customPattern = (int)ValuePattern.A; break; - case 'B': case 'b': customPattern = (int)ValuePattern.B; break; - case 'C': customPattern = (int)ValuePattern.C; break; - case 'c': customPattern = (int)ValuePattern.c; break; - case 'D': case 'd': customPattern = (int)ValuePattern.D; break; - case 'E': case 'e': customPattern = (int)ValuePattern.E; break; - case 'F': case 'f': customPattern = (int)ValuePattern.F; break; - case 'G': case 'g': customPattern = (int)ValuePattern.G; break; - case 'H': customPattern = (int)ValuePattern.H; break; - case 'h': customPattern = (int)ValuePattern.h; break; - case 'I': customPattern = (int)ValuePattern.One; break; - case 'i': customPattern = (int)ValuePattern.i; break; - case 'J': case 'j': customPattern = (int)ValuePattern.J; break; - case 'L': case 'l': customPattern = (int)ValuePattern.L; break; - case 'N': case 'n': customPattern = (int)ValuePattern.N; break; - case 'O': customPattern = (int)ValuePattern.Zero; break; - case 'o': customPattern = (int)ValuePattern.o; break; - case 'P': case 'p': customPattern = (int)ValuePattern.P; break; - case 'Q': case 'q': customPattern = (int)ValuePattern.Q; break; - case 'R': case 'r': customPattern = (int)ValuePattern.R; break; - case 'S': case 's': customPattern = (int)ValuePattern.Five; break; - case 'T': case 't': customPattern = (int)ValuePattern.T; break; - case 'U': customPattern = (int)ValuePattern.U; break; - case 'u': case 'µ': case 'μ': customPattern = (int)ValuePattern.u; break; - case 'Y': case 'y': customPattern = (int)ValuePattern.Y; break; - case '-': customPattern = (int)ValuePattern.Dash; break; - case '=': customPattern = (int)ValuePattern.Equals; break; - case '°': customPattern = (int)ValuePattern.Degrees; break; - case '\'': customPattern = (int)ValuePattern.Apostrophe; break; - case '"': customPattern = (int)ValuePattern.Quote; break; - case '[': case '{': customPattern = (int)ValuePattern.C; break; - case ']': case '}': customPattern = (int)ValuePattern.RBracket; break; - case '_': customPattern = (int)ValuePattern.Underscore; break; - case '≡': customPattern = (int)ValuePattern.Identical; break; - case '¬': customPattern = (int)ValuePattern.Not; break; - } - } - } - } - - /// - /// Set a custom bit pattern to be displayed on the seven segments. This is an - /// integer value where bits 0 through 6 correspond to each respective LED - /// segment. - /// - public int CustomPattern { get { return customPattern; } set { customPattern = value; Invalidate(); } } - - /// - /// Specifies if the decimal point LED is displayed. - /// - public bool DecimalShow { get { return showDot; } set { showDot = value; Invalidate(); } } - /// - /// Specifies if the decimal point LED is active. - /// - public bool DecimalOn { get { return dotOn; } set { dotOn = value; Invalidate(); } } - - /// - /// Specifies if the colon LEDs are displayed. - /// - public bool ColonShow { get { return showColon; } set { showColon = value; Invalidate(); } } - /// - /// Specifies if the colon LEDs are active. - /// - public bool ColonOn { get { return colonOn; } set { colonOn = value; Invalidate(); } } - - private void SevenSegment_Paint(object sender, PaintEventArgs e) - { - int useValue = customPattern; - - Brush brushLight = new SolidBrush(colorLight); - Brush brushDark = new SolidBrush(colorDark); - - // Define transformation for our container... - RectangleF srcRect; - - int colonWidth = gridWidth / 4; - - if(showColon){ - srcRect = new RectangleF(0.0F, 0.0F, gridWidth + colonWidth, gridHeight); - }else{ - srcRect = new RectangleF(0.0F, 0.0F, gridWidth, gridHeight); - } - RectangleF destRect = new RectangleF(Padding.Left, Padding.Top, Width - Padding.Left - Padding.Right, Height - Padding.Top - Padding.Bottom); - - // Begin graphics container that remaps coordinates for our convenience - GraphicsContainer containerState = e.Graphics.BeginContainer(destRect, srcRect, GraphicsUnit.Pixel); - - Matrix trans = new Matrix(); - trans.Shear(italicFactor, 0.0F); - e.Graphics.Transform = trans; - - e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; - e.Graphics.PixelOffsetMode = PixelOffsetMode.Default; - - // Draw elements based on whether the corresponding bit is high - e.Graphics.FillPolygon((useValue & 0x1) == 0x1 ? brushLight : brushDark, segPoints[0]); - e.Graphics.FillPolygon((useValue & 0x2) == 0x2 ? brushLight : brushDark, segPoints[1]); - e.Graphics.FillPolygon((useValue & 0x4) == 0x4 ? brushLight : brushDark, segPoints[2]); - e.Graphics.FillPolygon((useValue & 0x8) == 0x8 ? brushLight : brushDark, segPoints[3]); - e.Graphics.FillPolygon((useValue & 0x10) == 0x10 ? brushLight : brushDark, segPoints[4]); - e.Graphics.FillPolygon((useValue & 0x20) == 0x20 ? brushLight : brushDark, segPoints[5]); - e.Graphics.FillPolygon((useValue & 0x40) == 0x40 ? brushLight : brushDark, segPoints[6]); - - if (showDot) - e.Graphics.FillEllipse(dotOn ? brushLight : brushDark, gridWidth - 1, gridHeight - elementWidth + 1, elementWidth, elementWidth); - - if (showColon) - { - e.Graphics.FillEllipse(colonOn ? brushLight : brushDark, gridWidth + colonWidth - 4, gridHeight / 4 - elementWidth + 8, elementWidth, elementWidth); - e.Graphics.FillEllipse(colonOn ? brushLight : brushDark, gridWidth + colonWidth - 4, gridHeight * 3 / 4 - elementWidth + 4, elementWidth, elementWidth); - } - - e.Graphics.EndContainer(containerState); - } - - } -} diff --git a/CPU_emu/SevenSegmentArray.cs b/CPU_emu/SevenSegmentArray.cs deleted file mode 100644 index 41f74c4..0000000 --- a/CPU_emu/SevenSegmentArray.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System; -using System.Windows.Forms; -using System.Drawing; - -/* - * Seven-segment LED array control for .NET - * (uses the original seven-segment LED control) - * - * Copyright 2009-2019 Dmitry Brant. All Rights Reserved. - * me@dmitrybrant.com - * http://dmitrybrant.com - * - * This component is free for personal use. - * If you would like to use it in a commercial application, please - * e-mail me at the address above. - * This software comes as-is, with no warranty. - * - * Features: - * - Arbitrary number of array elements - * - All the customizable settings of the original 7-seg control - * - Accepts a string as a value, and distributes the characters - * among the array elements, automatically handling decimal points. - * - */ - -namespace DmitryBrant.CustomControls -{ - public class SevenSegmentArray : UserControl - { - /// - /// Array of segment controls that are currently children of this control. - /// - private SevenSegment[] segments = null; - - private int elementWidth = 10; - private float italicFactor = 0.0F; - private Color colorBackground = Color.DarkGray; - private Color colorDark = Color.DimGray; - private Color colorLight = Color.Red; - private bool showDot = true; - private Padding elementPadding; - - private string theValue = null; - - public SevenSegmentArray() - { - SuspendLayout(); - Name = "SevenSegmentArray"; - Size = new Size(100, 25); - Resize += new EventHandler(SevenSegmentArray_Resize); - ResumeLayout(false); - - TabStop = false; - elementPadding = new Padding(4, 4, 4, 4); - RecreateSegments(4); - } - - /// - /// Change the number of elements in our LED array. This destroys - /// the previous elements, and creates new ones in their place, applying - /// all the current options to the new ones. - /// - /// Number of elements to create. - private void RecreateSegments(int count) - { - if (segments != null) - for (int i = 0; i < segments.Length; i++) { segments[i].Parent = null; segments[i].Dispose(); } - - if (count <= 0) return; - segments = new SevenSegment[count]; - - for (int i = 0; i < count; i++) - { - segments[i] = new SevenSegment(); - segments[i].Parent = this; - segments[i].Top = 0; - segments[i].Height = Height; - segments[i].Anchor = AnchorStyles.Top | AnchorStyles.Bottom; - segments[i].Visible = true; - } - - ResizeSegments(); - UpdateSegments(); - Value = theValue; - } - - /// - /// Align the elements of the array to fit neatly within the - /// width of the parent control. - /// - private void ResizeSegments() - { - int segWidth = Width / segments.Length; - for (int i = 0; i < segments.Length; i++) - { - segments[i].Left = Width * (segments.Length - 1 - i) / segments.Length; - segments[i].Width = segWidth; - } - } - - /// - /// Update the properties of each element with the properties - /// we have stored. - /// - private void UpdateSegments() - { - for (int i = 0; i < segments.Length; i++) - { - segments[i].ColorBackground = colorBackground; - segments[i].ColorDark = colorDark; - segments[i].ColorLight = colorLight; - segments[i].ElementWidth = elementWidth; - segments[i].ItalicFactor = italicFactor; - segments[i].DecimalShow = showDot; - segments[i].Padding = elementPadding; - } - } - - private void SevenSegmentArray_Resize(object sender, EventArgs e) { ResizeSegments(); } - - protected override void OnPaintBackground(PaintEventArgs e) { e.Graphics.Clear(colorBackground); } - - /// - /// Background color of the LED array. - /// - public Color ColorBackground { get { return colorBackground; } set { colorBackground = value; UpdateSegments(); } } - /// - /// Color of inactive LED segments. - /// - public Color ColorDark { get { return colorDark; } set { colorDark = value; UpdateSegments(); } } - /// - /// Color of active LED segments. - /// - public Color ColorLight { get { return colorLight; } set { colorLight = value; UpdateSegments(); } } - - /// - /// Width of LED segments. - /// - public int ElementWidth { get { return elementWidth; } set { elementWidth = value; UpdateSegments(); } } - /// - /// Shear coefficient for italicizing the displays. Try a value like -0.1. - /// - public float ItalicFactor { get { return italicFactor; } set { italicFactor = value; UpdateSegments(); } } - /// - /// Specifies if the decimal point LED is displayed. - /// - public bool DecimalShow { get { return showDot; } set { showDot = value; UpdateSegments(); } } - - /// - /// Number of seven-segment elements in this array. - /// - public int ArrayCount { get { return segments.Length; } set { if ((value > 0) && (value <= 100)) RecreateSegments(value); } } - /// - /// Padding that applies to each seven-segment element in the array. - /// Tweak these numbers to get the perfect appearance for the array of your size. - /// - public Padding ElementPadding { get { return elementPadding; } set { elementPadding = value; UpdateSegments(); } } - - /// - /// The value to be displayed on the LED array. This can contain numbers, - /// certain letters, and decimal points. - /// - public string Value - { - get { return theValue; } - set - { - theValue = value; - for (int i = 0; i < segments.Length; i++) { segments[i].CustomPattern = 0; segments[i].DecimalOn = false; } - if (theValue != null) - { - int segmentIndex = 0; - for (int i = theValue.Length - 1; i >= 0; i--) - { - if (segmentIndex >= segments.Length) break; - if (theValue[i] == '.') segments[segmentIndex].DecimalOn = true; - else segments[segmentIndex++].Value = theValue[i].ToString(); - } - } - } - } - - } -} From 286735007df62d967ad3288a0d62650d84cee413 Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Tue, 22 Jul 2025 14:07:46 +0200 Subject: [PATCH 6/9] add HelperMethod RunSingleOpcodeTest() --- CPU_emuTests/CPU_Tests.cs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/CPU_emuTests/CPU_Tests.cs b/CPU_emuTests/CPU_Tests.cs index d54be35..767fc10 100644 --- a/CPU_emuTests/CPU_Tests.cs +++ b/CPU_emuTests/CPU_Tests.cs @@ -4,6 +4,7 @@ using System.Reflection; + namespace CPU_emulator; [TestFixture] @@ -363,27 +364,32 @@ private void InitializeMemory() ioDevice = new IoDevice(); } - #region LDA - // Test Load Accumulator immidiate A9 - [TestCase(0xff, ExpectedResult = new object[] { false, true, 0xff, 3 })] - [TestCase(0x00, ExpectedResult = new object[] { true, false, 0x00, 3 })] - public object[] Cmd_A9_Test(byte b) + public void RunSingleOpcodeTest(byte opcode, byte operand, ushort pcStart = 0x200) { - object[] result = new object[4]; - - cpu.WriteByteToMemory(b, 0x200); - cpu.SetPC(0x200); - - TestHelper.GetPrivateMethod("CallInstruction", cpu).Invoke(cpu, new object[] { cpu.GetType() , (byte)0xA9 }); + cpu.Reset(); + cpu.WriteByteToMemory(operand, pcStart); + cpu.SetPC(pcStart); - result[0] = cpu.flags["Z"]; - result[1] = cpu.flags["N"]; - result[2] = cpu.A; - result[3] = cpu.CpuCycle; + TestHelper.GetPrivateMethod("CallInstruction", cpu).Invoke(cpu, new object[] { cpu.GetType(), opcode }); + } - return result; + #region LDA + // Test Load Accumulator immidiate A9 + [TestCase(0xff, false, true, 0xff, 3)] + [TestCase(0x00, true, false, 0x00, 3)] + public void Cmd_A9_Test(byte value, bool expectedZ, bool expectedN, byte expectedA, int expectedCycles) + { + RunSingleOpcodeTest(0xA9, value); + Assert.Multiple(() => + { + Assert.That(cpu.flags["Z"], Is.EqualTo(expectedZ), "Zero Flag"); + Assert.That(cpu.flags["N"], Is.EqualTo(expectedN), "Negative Flag"); + Assert.That(cpu.A, Is.EqualTo(expectedA), "Register A"); + Assert.That(cpu.CpuCycle, Is.EqualTo(expectedCycles), "CPU Cycles"); + }); } + // Test Load Accumulator zeropage A5 [TestCase(0xff, ExpectedResult = new object[] { false, true, 0xff })] @@ -604,4 +610,5 @@ public static MethodInfo GetPrivateMethod(string methodName, object objectUnderT return method; } + } \ No newline at end of file From ccc2d115ad56a5d9e2eab15a0fd0649e38a11208 Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Wed, 23 Jul 2025 15:59:19 +0200 Subject: [PATCH 7/9] test case cmd_AD & refactoring some test cases --- CPU_emuTests/CPU_Tests.cs | 101 +++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 35 deletions(-) diff --git a/CPU_emuTests/CPU_Tests.cs b/CPU_emuTests/CPU_Tests.cs index 767fc10..d15da71 100644 --- a/CPU_emuTests/CPU_Tests.cs +++ b/CPU_emuTests/CPU_Tests.cs @@ -1,7 +1,9 @@ using CPU_emu; using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.DataCollection; +using NuGet.Frameworks; using System.Reflection; +using System.Reflection.Emit; @@ -364,22 +366,26 @@ private void InitializeMemory() ioDevice = new IoDevice(); } - public void RunSingleOpcodeTest(byte opcode, byte operand, ushort pcStart = 0x200) - { - cpu.Reset(); - cpu.WriteByteToMemory(operand, pcStart); - cpu.SetPC(pcStart); + //public void RunSingleOpcodeTest(byte opcode, byte operand, ushort pcStart = 0x200) + //{ + // cpu.Reset(); + // cpu.WriteByteToMemory(operand, pcStart); + // cpu.SetPC(pcStart); - TestHelper.GetPrivateMethod("CallInstruction", cpu).Invoke(cpu, new object[] { cpu.GetType(), opcode }); - } + // TestHelper.GetPrivateMethod("CallInstruction", cpu).Invoke(cpu, new object[] { cpu.GetType(), opcode }); + //} #region LDA + // Test Load Accumulator immidiate A9 [TestCase(0xff, false, true, 0xff, 3)] [TestCase(0x00, true, false, 0x00, 3)] public void Cmd_A9_Test(byte value, bool expectedZ, bool expectedN, byte expectedA, int expectedCycles) { - RunSingleOpcodeTest(0xA9, value); + cpu.WriteByteToMemory(value, 0x200); + cpu.SetPC(0x200); + + TestHelper.GetPrivateMethod("CallInstruction", cpu).Invoke(cpu, new object[] { cpu.GetType(), (byte)0xA9 }); Assert.Multiple(() => { @@ -389,49 +395,74 @@ public void Cmd_A9_Test(byte value, bool expectedZ, bool expectedN, byte expecte Assert.That(cpu.CpuCycle, Is.EqualTo(expectedCycles), "CPU Cycles"); }); } - - + + // Test Load Accumulator zeropage A5 - [TestCase(0xff, ExpectedResult = new object[] { false, true, 0xff })] - [TestCase(0x00, ExpectedResult = new object[] { true, false, 0x00 })] - public object[] Cmd_A5_Test(byte b) + [TestCase(0xff, false, true, 0xff, 3)] + [TestCase(0x00, true, false, 0x00, 3)] + public void Cmd_A5_Test(byte value, bool expectedZ, bool expectedN, byte expectedA, int expectedCycles) { - object[] result = new object[3]; - - cpu.WriteByteToMemory(b, 0x01); // set byte on zeropage adr. 0x01 + cpu.WriteByteToMemory(value, 0x01); // set byte on zeropage adr. 0x01 cpu.WriteByteToMemory(0x01, 0x200); cpu.SetPC(0x200); - cpu.Cmd_A5(); + TestHelper.GetPrivateMethod("CallInstruction", cpu).Invoke(cpu, new object[] { cpu.GetType(), (byte)0xA5 }); + + Assert.Multiple(() => + { + Assert.That(cpu.flags["Z"], Is.EqualTo(expectedZ), "Zero Flag"); + Assert.That(cpu.flags["N"], Is.EqualTo(expectedN), "Negative Flag"); + Assert.That(cpu.A, Is.EqualTo(expectedA), "Register A"); + Assert.That(cpu.CpuCycle, Is.EqualTo(expectedCycles), "CPU Cycles"); + }); - result[0] = cpu.flags["Z"]; - result[1] = cpu.flags["N"]; - result[2] = cpu.A; + } - return result; + // Load Accumulator zeropage X B5 + [TestCase(0xff, false, true, 0xff, 5)] + [TestCase(0x00, true, false, 0x00, 5)] + public void Cmd_B5_Test(byte value, bool expectedZ, bool expectedN, byte expectedA, int expectedCycles) + { + cpu.Reset(); + cpu.SetRegister("X",0x06); // load X with 0x06 + cpu.WriteByteToMemory(value, 0x07); // set byte on zeropage adr. 0x07 + cpu.WriteByteToMemory(0x01, 0x200); // set 0x01 on the next position of PC so value ox X (0x06) + 0x01 from instruction points to 0x07 + cpu.SetPC(0x200); + + TestHelper.GetPrivateMethod("CallInstruction", cpu).Invoke(cpu, new object[] { cpu.GetType(), (byte)0xB5 }); + Assert.Multiple(() => + { + Assert.That(cpu.flags["Z"], Is.EqualTo(expectedZ), "Zero Flag"); + Assert.That(cpu.flags["N"], Is.EqualTo(expectedN), "Negative Flag"); + Assert.That(cpu.A, Is.EqualTo(expectedA), "Register A"); + Assert.That(cpu.CpuCycle, Is.EqualTo(expectedCycles), "CPU Cycles"); + }); } - // Load Accumulator zeropage X B5 - [TestCase(0xff, ExpectedResult = new object[] { false, true, 0xff })] - [TestCase(0x00, ExpectedResult = new object[] { true, false, 0x00 })] - public object[] Cmd_B5_Test(byte b) + // Load Accumulator absolute AD + [TestCase(0xff, false, true, 0xff, 6)] + [TestCase(0x00, true, false, 0x00, 6)] + public void Cmd_AD_Test(byte value, bool expectedZ, bool expectedN, byte expectedA, int expectedCycles) { - object[] result = new object[3]; - cpu.SetRegister("X",0x06); - cpu.WriteByteToMemory(b, 0x07); // set byte on zeropage adr. 0x01 - cpu.WriteByteToMemory(0x01, 0x200); + cpu.Reset(); + cpu.WriteByteToMemory(value, 0xFFEE); + cpu.WriteByteToMemory(0xEE, 0x200); + cpu.WriteByteToMemory(0xFF, 0x201); cpu.SetPC(0x200); - cpu.Cmd_B5(); - result[0] = cpu.flags["Z"]; - result[1] = cpu.flags["N"]; - result[2] = cpu.A; + TestHelper.GetPrivateMethod("CallInstruction", cpu).Invoke(cpu, new object[] { cpu.GetType(), (byte)0xAD }); - return result; + Assert.Multiple(() => + { + Assert.That(cpu.flags["Z"], Is.EqualTo(expectedZ), "Zero Flag"); + Assert.That(cpu.flags["N"], Is.EqualTo(expectedN), "Negative Flag"); + Assert.That(cpu.A, Is.EqualTo(expectedA), "Register A"); + Assert.That(cpu.CpuCycle, Is.EqualTo(expectedCycles), "CPU Cycles"); + }); } - #endregion + #endregion #region LDX From 278cc9a2aedc93789285edb50cfa5c1806b14bcf Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Wed, 23 Jul 2025 16:00:41 +0200 Subject: [PATCH 8/9] Bugfix FetchWord() missing PC++ --- CPU_emu/CPU/CPU.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CPU_emu/CPU/CPU.cs b/CPU_emu/CPU/CPU.cs index d91f811..8a8b9dc 100644 --- a/CPU_emu/CPU/CPU.cs +++ b/CPU_emu/CPU/CPU.cs @@ -228,8 +228,9 @@ private byte FetchByte() private ushort FetchWord() { ushort LoByte = ReadByteFromMemory((ushort)PC); - PC++; + IncrementPC(); ushort HiByte = (ushort)(ReadByteFromMemory((ushort)PC) << 8); + IncrementPC(); IncrementCpuCycle(2); From 17ef5a8abcb59a84c96a310b9d99ce6c1e50a6b4 Mon Sep 17 00:00:00 2001 From: Michael Bohn Date: Wed, 23 Jul 2025 16:02:01 +0200 Subject: [PATCH 9/9] fixing cycle infos at method attrib --- CPU_emu/CPU/CPU_CMD_Methods.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CPU_emu/CPU/CPU_CMD_Methods.cs b/CPU_emu/CPU/CPU_CMD_Methods.cs index a6153f4..706adea 100644 --- a/CPU_emu/CPU/CPU_CMD_Methods.cs +++ b/CPU_emu/CPU/CPU_CMD_Methods.cs @@ -35,7 +35,7 @@ public void Cmd_A5() // Load Accumulator zeropage A5 } // LDA $zz,X - [Opcode(2)] + [Opcode(4)] public void Cmd_B5() // Load Accumulator zeropage X B5 { ushort addr = AddrZeroPageX(); @@ -45,8 +45,8 @@ public void Cmd_B5() // Load Accumulator zeropage X B5 } // LDA $nnnn (absolute) - [Opcode(3)] - public void Cmd_AD() + [Opcode(4)] + public void Cmd_AD() // Load Accumulator absolute AD { ushort addr = AddrAbsolute(); byte value = ReadByteFromMemory(addr); @@ -55,8 +55,8 @@ public void Cmd_AD() } // LDA $nnnn,X - [Opcode(3)] - public void Cmd_BD() + [Opcode(4)] + public void Cmd_BD() // Load Accumulator absolute X BD { ushort addr = AddrAbsoluteX(); byte value = ReadByteFromMemory(addr); @@ -65,7 +65,7 @@ public void Cmd_BD() } // LDA $nnnn,Y - [Opcode(3)] + [Opcode(4)] public void Cmd_B9() { ushort addr = AddrAbsoluteY(); @@ -75,7 +75,7 @@ public void Cmd_B9() } // LDA ($zz,X) – Indirect,X - [Opcode(2)] + [Opcode(6)] public void Cmd_A1() { ushort addr = AddrIndirectX(); @@ -85,7 +85,7 @@ public void Cmd_A1() } // LDA ($zz),Y – Indirect,Y - [Opcode(2)] + [Opcode(5)] public void Cmd_B1() { ushort addr = AddrIndirectY();