IDE suggestions

This commit is contained in:
Adrian Conlon
2024-05-19 09:07:20 +01:00
parent 6cbffa1051
commit e0235f396e
19 changed files with 151 additions and 192 deletions

View File

@@ -3,14 +3,9 @@
// </copyright> // </copyright>
namespace EightBit namespace EightBit
{ {
public abstract class BigEndianProcessor : Processor public abstract class BigEndianProcessor(Bus memory) : Processor(memory)
{ {
private readonly Register16 intermediate = new Register16(); private readonly Register16 intermediate = new();
protected BigEndianProcessor(Bus memory)
: base(memory)
{
}
public override Register16 PeekWord(ushort address) public override Register16 PeekWord(ushort address)
{ {

View File

@@ -10,13 +10,13 @@ namespace EightBit
{ {
private byte data; private byte data;
public event EventHandler<EventArgs> WritingByte; public event EventHandler<EventArgs>? WritingByte;
public event EventHandler<EventArgs> WrittenByte; public event EventHandler<EventArgs>? WrittenByte;
public event EventHandler<EventArgs> ReadingByte; public event EventHandler<EventArgs>? ReadingByte;
public event EventHandler<EventArgs> ReadByte; public event EventHandler<EventArgs>? ReadByte;
public byte Data { get => this.data; set => this.data = value; } public byte Data { get => this.data; set => this.data = value; }
@@ -113,7 +113,7 @@ namespace EightBit
protected ref byte Reference(ushort absolute) protected ref byte Reference(ushort absolute)
{ {
var mapped = this.Mapping(absolute); var mapped = this.Mapping(absolute);
var offset = (ushort)((absolute - mapped.Begin) & mapped.Mask); var offset = (ushort)mapped.Offset(absolute);
if (mapped.Access == AccessLevel.ReadOnly) if (mapped.Access == AccessLevel.ReadOnly)
{ {
this.Data = mapped.Memory.Peek(offset); this.Data = mapped.Memory.Peek(offset);
@@ -131,16 +131,14 @@ namespace EightBit
protected void LoadHexFile(string path) protected void LoadHexFile(string path)
{ {
using (var file = new IntelHexFile(path)) using var file = new IntelHexFile(path);
foreach (var chunk in file.Parse())
{ {
foreach (var chunk in file.Parse()) var address = chunk.Item1;
{ var content = chunk.Item2;
var address = chunk.Item1; var mapped = this.Mapping(address);
var content = chunk.Item2; var offset = address - mapped.Begin;
var mapped = this.Mapping(address); mapped.Memory.Load(content, offset);
var offset = address - mapped.Begin;
mapped.Memory.Load(content, offset);
}
} }
} }
} }

View File

@@ -12,7 +12,7 @@ namespace EightBit
{ {
} }
public event EventHandler<EventArgs> Ticked; public event EventHandler<EventArgs>? Ticked;
public int Cycles { get; protected set; } public int Cycles { get; protected set; }

View File

@@ -14,13 +14,13 @@ namespace EightBit
{ {
} }
public event EventHandler<EventArgs> RaisingPOWER; public event EventHandler<EventArgs>? RaisingPOWER;
public event EventHandler<EventArgs> RaisedPOWER; public event EventHandler<EventArgs>? RaisedPOWER;
public event EventHandler<EventArgs> LoweringPOWER; public event EventHandler<EventArgs>? LoweringPOWER;
public event EventHandler<EventArgs> LoweredPOWER; public event EventHandler<EventArgs>? LoweredPOWER;
public bool Powered => this.POWER.Raised(); public bool Powered => this.POWER.Raised();

View File

@@ -15,13 +15,13 @@ namespace EightBit
{ {
} }
public event EventHandler<PortEventArgs> ReadingPort; public event EventHandler<PortEventArgs>? ReadingPort;
public event EventHandler<PortEventArgs> ReadPort; public event EventHandler<PortEventArgs>? ReadPort;
public event EventHandler<PortEventArgs> WritingPort; public event EventHandler<PortEventArgs>? WritingPort;
public event EventHandler<PortEventArgs> WrittenPort; public event EventHandler<PortEventArgs>? WrittenPort;
public byte Read(byte port) => this.ReadInputPort(port); public byte Read(byte port) => this.ReadInputPort(port);

View File

@@ -8,14 +8,12 @@ namespace EightBit
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
public class IntelHexFile : IDisposable public class IntelHexFile(string path) : IDisposable
{ {
private readonly StreamReader reader; private readonly StreamReader reader = File.OpenText(path);
private bool eof; private bool eof;
private bool disposed = false; private bool disposed = false;
public IntelHexFile(string path) => this.reader = File.OpenText(path);
public void Dispose() public void Dispose()
{ {
this.Dispose(true); this.Dispose(true);
@@ -27,7 +25,7 @@ namespace EightBit
this.eof = false; this.eof = false;
while (!this.reader.EndOfStream && !this.eof) while (!this.reader.EndOfStream && !this.eof)
{ {
var line = this.reader.ReadLine(); var line = this.reader.ReadLine() ?? throw new InvalidOperationException("Early EOF detected");
var parsed = this.Parse(line); var parsed = this.Parse(line);
if (parsed != null) if (parsed != null)
{ {
@@ -78,14 +76,14 @@ namespace EightBit
return data; return data;
} }
private Tuple<ushort, byte[]> Parse(string line) private Tuple<ushort, byte[]>? Parse(string line)
{ {
if (string.IsNullOrEmpty(line)) if (string.IsNullOrEmpty(line))
{ {
throw new ArgumentNullException(nameof(line)); throw new ArgumentNullException(nameof(line));
} }
var colon = line.Substring(0, 1); var colon = line[..1];
if (colon != ":") if (colon != ":")
{ {
throw new ArgumentOutOfRangeException(nameof(line), "Invalid hex file: line does not begin with a colon"); throw new ArgumentOutOfRangeException(nameof(line), "Invalid hex file: line does not begin with a colon");

View File

@@ -8,8 +8,8 @@ namespace EightBit
public abstract class IntelProcessor : LittleEndianProcessor public abstract class IntelProcessor : LittleEndianProcessor
{ {
private static readonly int[] HalfCarryTableAdd = new int[8] { 0, 0, 1, 0, 1, 0, 1, 1 }; private static readonly int[] HalfCarryTableAdd = [0, 0, 1, 0, 1, 0, 1, 1];
private static readonly int[] HalfCarryTableSub = new int[8] { 0, 1, 1, 1, 0, 0, 0, 1 }; private static readonly int[] HalfCarryTableSub = [0, 1, 1, 1, 0, 0, 0, 1];
private readonly IntelOpCodeDecoded[] decodedOpCodes = new IntelOpCodeDecoded[0x100]; private readonly IntelOpCodeDecoded[] decodedOpCodes = new IntelOpCodeDecoded[0x100];
@@ -24,13 +24,13 @@ namespace EightBit
} }
} }
public event EventHandler<EventArgs> RaisingHALT; public event EventHandler<EventArgs>? RaisingHALT;
public event EventHandler<EventArgs> RaisedHALT; public event EventHandler<EventArgs>? RaisedHALT;
public event EventHandler<EventArgs> LoweringHALT; public event EventHandler<EventArgs>? LoweringHALT;
public event EventHandler<EventArgs> LoweredHALT; public event EventHandler<EventArgs>? LoweredHALT;
public Register16 SP { get; } = new Register16((ushort)Mask.Sixteen); public Register16 SP { get; } = new Register16((ushort)Mask.Sixteen);

View File

@@ -4,14 +4,9 @@
namespace EightBit namespace EightBit
{ {
public abstract class LittleEndianProcessor : Processor public abstract class LittleEndianProcessor(Bus memory) : Processor(memory)
{ {
private readonly Register16 intermediate = new Register16(); private readonly Register16 intermediate = new();
protected LittleEndianProcessor(Bus memory)
: base(memory)
{
}
public override Register16 PeekWord(ushort address) public override Register16 PeekWord(ushort address)
{ {

View File

@@ -4,27 +4,24 @@
namespace EightBit namespace EightBit
{ {
public class MemoryMapping public class MemoryMapping(Memory memory, ushort begin, ushort mask, AccessLevel access)
{ {
public MemoryMapping(Memory memory, ushort begin, ushort mask, AccessLevel access)
{
this.Memory = memory;
this.Begin = begin;
this.Mask = mask;
this.Access = access;
}
public MemoryMapping(Memory memory, ushort begin, Mask mask, AccessLevel access) public MemoryMapping(Memory memory, ushort begin, Mask mask, AccessLevel access)
: this(memory, begin, (ushort)mask, access) : this(memory, begin, (ushort)mask, access)
{ {
} }
public Memory Memory { get; set; } public Memory Memory { get; set; } = memory;
public ushort Begin { get; set; } public ushort Begin { get; set; } = begin;
public ushort Mask { get; set; } public ushort Mask { get; set; } = mask;
public AccessLevel Access { get; set; } public AccessLevel Access { get; set; } = access;
public int Offset(ushort absolute)
{
return (absolute - this.Begin) & this.Mask;
}
} }
} }

View File

@@ -6,10 +6,8 @@ namespace EightBit
{ {
using System; using System;
public sealed class PortEventArgs : EventArgs public sealed class PortEventArgs(byte value) : EventArgs
{ {
public PortEventArgs(byte value) => this.Port = value; public byte Port { get; } = value;
public byte Port { get; }
} }
} }

View File

@@ -6,34 +6,32 @@ namespace EightBit
{ {
using System; using System;
public abstract class Processor : ClockedChip public abstract class Processor(Bus memory) : ClockedChip
{ {
private PinLevel resetLine; private PinLevel resetLine;
private PinLevel intLine; private PinLevel intLine;
protected Processor(Bus memory) => this.Bus = memory; public event EventHandler<EventArgs>? RaisingRESET;
public event EventHandler<EventArgs> RaisingRESET; public event EventHandler<EventArgs>? RaisedRESET;
public event EventHandler<EventArgs> RaisedRESET; public event EventHandler<EventArgs>? LoweringRESET;
public event EventHandler<EventArgs> LoweringRESET; public event EventHandler<EventArgs>? LoweredRESET;
public event EventHandler<EventArgs> LoweredRESET; public event EventHandler<EventArgs>? RaisingINT;
public event EventHandler<EventArgs> RaisingINT; public event EventHandler<EventArgs>? RaisedINT;
public event EventHandler<EventArgs> RaisedINT; public event EventHandler<EventArgs>? LoweringINT;
public event EventHandler<EventArgs> LoweringINT; public event EventHandler<EventArgs>? LoweredINT;
public event EventHandler<EventArgs> LoweredINT;
public ref PinLevel RESET => ref this.resetLine; public ref PinLevel RESET => ref this.resetLine;
public ref PinLevel INT => ref this.intLine; public ref PinLevel INT => ref this.intLine;
public Bus Bus { get; } public Bus Bus { get; } = memory;
public Register16 PC { get; } = new Register16(); public Register16 PC { get; } = new Register16();

View File

@@ -4,13 +4,8 @@
namespace EightBit namespace EightBit
{ {
public class Ram : Rom public class Ram(int size) : Rom(size)
{ {
public Ram(int size)
: base(size)
{
}
public Ram() public Ram()
: this(0) : this(0)
{ {

View File

@@ -69,12 +69,26 @@ namespace EightBit
public static bool operator !=(Register16 left, Register16 right) => !(left == right); public static bool operator !=(Register16 left, Register16 right) => !(left == right);
public override bool Equals(object obj) public override int GetHashCode() => this.Word;
public override bool Equals(object? obj)
{ {
var rhs = obj as Register16; return Equals(obj as Register16);
return rhs == null ? false : rhs.Low == this.Low && rhs.High == this.High;
} }
public override int GetHashCode() => this.Word; public bool Equals(Register16? rhs)
{
if (ReferenceEquals(this, rhs))
{
return true;
}
if (rhs is null)
{
return false;
}
return rhs.Low == this.Low && rhs.High == this.High;
}
} }
} }

View File

@@ -7,11 +7,9 @@ namespace EightBit
using System; using System;
using System.IO; using System.IO;
public class Rom : Memory public class Rom(int size) : Memory
{ {
private byte[] bytes; private byte[] bytes = new byte[size];
public Rom(int size) => this.bytes = new byte[size];
public Rom() public Rom()
: this(0) : this(0)
@@ -53,10 +51,8 @@ namespace EightBit
public static int Load(string path, ref byte[] output, int writeOffset = 0, int readOffset = 0, int limit = -1, int maximumSize = -1) public static int Load(string path, ref byte[] output, int writeOffset = 0, int readOffset = 0, int limit = -1, int maximumSize = -1)
{ {
using (var file = File.Open(path, FileMode.Open)) using var file = File.Open(path, FileMode.Open);
{ return Load(file, ref output, writeOffset, readOffset, limit, maximumSize);
return Load(file, ref output, writeOffset, readOffset, limit, maximumSize);
}
} }
public override int Load(FileStream file, int writeOffset = 0, int readOffset = 0, int limit = -1) public override int Load(FileStream file, int writeOffset = 0, int readOffset = 0, int limit = -1)

View File

@@ -6,16 +6,10 @@ namespace EightBit
{ {
using System.IO; using System.IO;
public class UnusedMemory : Memory public class UnusedMemory(int size, byte unchanging) : Memory
{ {
private readonly int size; private readonly int size = size;
private readonly byte unchanging; private readonly byte unchanging = unchanging;
public UnusedMemory(int size, byte unchanging)
{
this.size = size;
this.unchanging = unchanging;
}
public override int Size => this.size; public override int Size => this.size;

View File

@@ -6,16 +6,14 @@ namespace EightBit
{ {
using System; using System;
public class Disassembler public class Disassembler(Bus bus)
{ {
private bool prefixCB = false; private bool prefixCB = false;
private bool prefixDD = false; private bool prefixDD = false;
private bool prefixED = false; private bool prefixED = false;
private bool prefixFD = false; private bool prefixFD = false;
public Disassembler(Bus bus) => this.Bus = bus; public Bus Bus { get; } = bus;
public Bus Bus { get; }
public static string AsFlag(byte value, StatusBits flag, string represents) => (value & (byte)flag) != 0 ? represents : "-"; public static string AsFlag(byte value, StatusBits flag, string represents) => (value & (byte)flag) != 0 ? represents : "-";
@@ -31,10 +29,7 @@ namespace EightBit
public static string State(Z80 cpu) public static string State(Z80 cpu)
{ {
if (cpu == null) ArgumentNullException.ThrowIfNull(cpu);
{
throw new ArgumentNullException(nameof(cpu));
}
var pc = cpu.PC; var pc = cpu.PC;
var sp = cpu.SP; var sp = cpu.SP;
@@ -75,11 +70,7 @@ namespace EightBit
public string Disassemble(Z80 cpu) public string Disassemble(Z80 cpu)
{ {
if (cpu == null) ArgumentNullException.ThrowIfNull(cpu);
{
throw new ArgumentNullException(nameof(cpu));
}
this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false; this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
return this.Disassemble(cpu, cpu.PC.Word); return this.Disassemble(cpu, cpu.PC.Word);
} }

View File

@@ -4,16 +4,10 @@
namespace EightBit namespace EightBit
{ {
public struct RefreshRegister : System.IEquatable<RefreshRegister> public struct RefreshRegister(byte value) : System.IEquatable<RefreshRegister>
{ {
private readonly byte high; private readonly byte high = (byte)(value & (byte)Bits.Bit7);
private byte variable; private byte variable = (byte)(value & (byte)Mask.Seven);
public RefreshRegister(byte value)
{
this.high = (byte)(value & (byte)Bits.Bit7);
this.variable = (byte)(value & (byte)Mask.Seven);
}
public static implicit operator byte(RefreshRegister input) => ToByte(input); public static implicit operator byte(RefreshRegister input) => ToByte(input);
@@ -33,14 +27,22 @@ namespace EightBit
return value; return value;
} }
public static RefreshRegister FromByte(byte input) => new RefreshRegister(input); public static RefreshRegister FromByte(byte input) => new(input);
public byte ToByte() => ToByte(this); public readonly byte ToByte() => ToByte(this);
public override bool Equals(object obj) => obj is RefreshRegister ? this.Equals((RefreshRegister)obj) : false; public override readonly bool Equals(object? obj)
{
if (obj is null)
{
return false;
}
public override int GetHashCode() => this.high + this.variable; return this.Equals((RefreshRegister)obj);
}
public readonly bool Equals(RefreshRegister other) => other.high == this.high && other.variable == this.variable;
public override readonly int GetHashCode() => this.high + this.variable;
public bool Equals(RefreshRegister other) => other.high == this.high && other.variable == this.variable;
} }
} }

View File

@@ -24,12 +24,16 @@ namespace EightBit
// Undocumented X flag // Undocumented X flag
XF = Bits.Bit3, XF = Bits.Bit3,
#pragma warning disable CA1069 // Enums values should not be duplicated
// Parity // Parity
PF = Bits.Bit2, PF = Bits.Bit2,
// Overflow // Overflow
VF = Bits.Bit2, VF = Bits.Bit2,
#pragma warning restore CA1069 // Enums values should not be duplicated
// Negative? // Negative?
NF = Bits.Bit1, NF = Bits.Bit1,

View File

@@ -6,11 +6,11 @@ namespace EightBit
{ {
using System; using System;
public class Z80 : IntelProcessor public class Z80(Bus bus, InputOutput ports) : IntelProcessor(bus)
{ {
private readonly InputOutput ports; private readonly InputOutput ports = ports;
private readonly Register16[] accumulatorFlags = { new Register16(), new Register16() }; private readonly Register16[] accumulatorFlags = [new Register16(), new Register16()];
private readonly Register16[,] registers = private readonly Register16[,] registers =
{ {
{ {
@@ -21,9 +21,9 @@ namespace EightBit
}, },
}; };
private readonly Register16 intermediate = new Register16(); private readonly Register16 intermediate = new();
private RefreshRegister refresh = new RefreshRegister(0x7f); private RefreshRegister refresh = new(0x7f);
private bool prefixCB = false; private bool prefixCB = false;
private bool prefixDD = false; private bool prefixDD = false;
@@ -44,68 +44,65 @@ namespace EightBit
private sbyte displacement = 0; private sbyte displacement = 0;
private bool displaced = false; private bool displaced = false;
public Z80(Bus bus, InputOutput ports) public event EventHandler<EventArgs>? ExecutingInstruction;
: base(bus) => this.ports = ports;
public event EventHandler<EventArgs> ExecutingInstruction; public event EventHandler<EventArgs>? ExecutedInstruction;
public event EventHandler<EventArgs> ExecutedInstruction; public event EventHandler<EventArgs>? RaisingNMI;
public event EventHandler<EventArgs> RaisingNMI; public event EventHandler<EventArgs>? RaisedNMI;
public event EventHandler<EventArgs> RaisedNMI; public event EventHandler<EventArgs>? LoweringNMI;
public event EventHandler<EventArgs> LoweringNMI; public event EventHandler<EventArgs>? LoweredNMI;
public event EventHandler<EventArgs> LoweredNMI; public event EventHandler<EventArgs>? RaisingM1;
public event EventHandler<EventArgs> RaisingM1; public event EventHandler<EventArgs>? RaisedM1;
public event EventHandler<EventArgs> RaisedM1; public event EventHandler<EventArgs>? LoweringM1;
public event EventHandler<EventArgs> LoweringM1; public event EventHandler<EventArgs>? LoweredM1;
public event EventHandler<EventArgs> LoweredM1; public event EventHandler<EventArgs>? RaisingRFSH;
public event EventHandler<EventArgs> RaisingRFSH; public event EventHandler<EventArgs>? RaisedRFSH;
public event EventHandler<EventArgs> RaisedRFSH; public event EventHandler<EventArgs>? LoweringRFSH;
public event EventHandler<EventArgs> LoweringRFSH; public event EventHandler<EventArgs>? LoweredRFSH;
public event EventHandler<EventArgs> LoweredRFSH; public event EventHandler<EventArgs>? RaisingMREQ;
public event EventHandler<EventArgs> RaisingMREQ; public event EventHandler<EventArgs>? RaisedMREQ;
public event EventHandler<EventArgs> RaisedMREQ; public event EventHandler<EventArgs>? LoweringMREQ;
public event EventHandler<EventArgs> LoweringMREQ; public event EventHandler<EventArgs>? LoweredMREQ;
public event EventHandler<EventArgs> LoweredMREQ; public event EventHandler<EventArgs>? RaisingIORQ;
public event EventHandler<EventArgs> RaisingIORQ; public event EventHandler<EventArgs>? RaisedIORQ;
public event EventHandler<EventArgs> RaisedIORQ; public event EventHandler<EventArgs>? LoweringIORQ;
public event EventHandler<EventArgs> LoweringIORQ; public event EventHandler<EventArgs>? LoweredIORQ;
public event EventHandler<EventArgs> LoweredIORQ; public event EventHandler<EventArgs>? RaisingRD;
public event EventHandler<EventArgs> RaisingRD; public event EventHandler<EventArgs>? RaisedRD;
public event EventHandler<EventArgs> RaisedRD; public event EventHandler<EventArgs>? LoweringRD;
public event EventHandler<EventArgs> LoweringRD; public event EventHandler<EventArgs>? LoweredRD;
public event EventHandler<EventArgs> LoweredRD; public event EventHandler<EventArgs>? RaisingWR;
public event EventHandler<EventArgs> RaisingWR; public event EventHandler<EventArgs>? RaisedWR;
public event EventHandler<EventArgs> RaisedWR; public event EventHandler<EventArgs>? LoweringWR;
public event EventHandler<EventArgs> LoweringWR; public event EventHandler<EventArgs>? LoweredWR;
public event EventHandler<EventArgs> LoweredWR;
public byte IV { get; set; } = 0xff; public byte IV { get; set; } = 0xff;
@@ -390,7 +387,7 @@ namespace EightBit
// received from the memory is ignored and an NOP instruction is forced internally to the // received from the memory is ignored and an NOP instruction is forced internally to the
// CPU.The HALT acknowledge signal is active during this time indicating that the processor // CPU.The HALT acknowledge signal is active during this time indicating that the processor
// is in the HALT state. // is in the HALT state.
var discarded = this.ReadInitialOpCode(); _ = this.ReadInitialOpCode();
this.Execute(0); // NOP this.Execute(0); // NOP
handled = true; handled = true;
} }
@@ -864,26 +861,13 @@ namespace EightBit
break; break;
case 6: // Set interrupt mode case 6: // Set interrupt mode
switch (y) this.IM = y switch
{ {
case 0: 0 or 1 or 4 or 5 => 0,
case 1: 2 or 6 => 1,
case 4: 3 or 7 => 2,
case 5: _ => throw new NotSupportedException("Invalid operation mode"),
this.IM = 0; };
break;
case 2:
case 6:
this.IM = 1;
break;
case 3:
case 7:
this.IM = 2;
break;
default:
throw new NotSupportedException("Invalid operation mode");
}
break; break;
case 7: // Assorted ops case 7: // Assorted ops
switch (y) switch (y)
@@ -1566,7 +1550,7 @@ namespace EightBit
this.IFF2 = this.IFF1; this.IFF2 = this.IFF1;
this.IFF1 = false; this.IFF1 = false;
this.LowerM1(); this.LowerM1();
var discarded = this.Bus.Data; _ = this.Bus.Data;
this.RaiseM1(); this.RaiseM1();
this.Restart(0x66); this.Restart(0x66);
} }