mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2024-12-23 17:31:33 +00:00
Follow most of the guideline suggestions from VS2019 preview. Pretty good suggestions!
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
parent
28b7a88f0f
commit
03caba99dc
@ -54,7 +54,7 @@ namespace EightBit
|
|||||||
|
|
||||||
public static int CountBits(int value)
|
public static int CountBits(int value)
|
||||||
{
|
{
|
||||||
int count = 0;
|
var count = 0;
|
||||||
while (value != 0)
|
while (value != 0)
|
||||||
{
|
{
|
||||||
++count;
|
++count;
|
||||||
|
@ -18,7 +18,7 @@ namespace EightBit
|
|||||||
|
|
||||||
public void Tick(int extra)
|
public void Tick(int extra)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < extra; ++i)
|
for (var i = 0; i < extra; ++i)
|
||||||
{
|
{
|
||||||
this.Tick();
|
this.Tick();
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace EightBit
|
|||||||
protected IntelProcessor(Bus bus)
|
protected IntelProcessor(Bus bus)
|
||||||
: base(bus)
|
: base(bus)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 0x100; ++i)
|
for (var i = 0; i < 0x100; ++i)
|
||||||
{
|
{
|
||||||
this.decodedOpCodes[i] = new IntelOpCodeDecoded((byte)i);
|
this.decodedOpCodes[i] = new IntelOpCodeDecoded((byte)i);
|
||||||
}
|
}
|
||||||
@ -87,10 +87,7 @@ namespace EightBit
|
|||||||
this.OnLoweredHALT();
|
this.OnLoweredHALT();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int BuildHalfCarryIndex(byte before, byte value, int calculation)
|
protected static int BuildHalfCarryIndex(byte before, byte value, int calculation) => ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3);
|
||||||
{
|
|
||||||
return ((before & 0x88) >> 1) | ((value & 0x88) >> 2) | ((calculation & 0x88) >> 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int CalculateHalfCarryAdd(byte before, byte value, int calculation)
|
protected static int CalculateHalfCarryAdd(byte before, byte value, int calculation)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ namespace EightBit
|
|||||||
|
|
||||||
public int Run(int limit)
|
public int Run(int limit)
|
||||||
{
|
{
|
||||||
int current = 0;
|
var current = 0;
|
||||||
while (this.Powered && (current < limit))
|
while (this.Powered && (current < limit))
|
||||||
{
|
{
|
||||||
current += this.Step();
|
current += this.Step();
|
||||||
|
@ -45,10 +45,7 @@ namespace EightBit
|
|||||||
|
|
||||||
public ushort Word
|
public ushort Word
|
||||||
{
|
{
|
||||||
get
|
get => (ushort)(this.Low | Chip.PromoteByte(this.High));
|
||||||
{
|
|
||||||
return (ushort)(this.Low | Chip.PromoteByte(this.High));
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
@ -84,12 +81,7 @@ namespace EightBit
|
|||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
var rhs = obj as Register16;
|
var rhs = obj as Register16;
|
||||||
if (rhs == null)
|
return rhs == null ? false : rhs.Low == this.Low && rhs.High == this.High;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rhs.Low == this.Low && rhs.High == this.High;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() => this.Word;
|
public override int GetHashCode() => this.Word;
|
||||||
|
@ -34,15 +34,9 @@ namespace EightBit
|
|||||||
return returned.ToString();
|
return returned.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Dump_ByteValue(byte value)
|
public static string Dump_ByteValue(byte value) => value.ToString("X2");
|
||||||
{
|
|
||||||
return value.ToString("X2");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Dump_WordValue(ushort value)
|
public static string Dump_WordValue(ushort value) => value.ToString("X4");
|
||||||
{
|
|
||||||
return value.ToString("X4");
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Disassemble(ushort current)
|
public string Disassemble(ushort current)
|
||||||
{
|
{
|
||||||
@ -503,215 +497,81 @@ namespace EightBit
|
|||||||
return output.ToString();
|
return output.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ConvertAddress(ushort absolute)
|
private string ConvertAddress(ushort absolute) => this.symbols.Labels.TryGetValue(absolute, out var label) ? label : "$" + Dump_WordValue(absolute);
|
||||||
{
|
|
||||||
if (this.symbols.Labels.TryGetValue(absolute, out string label))
|
|
||||||
{
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "$" + Dump_WordValue(absolute);
|
private string ConvertAddress(byte absolute) => this.symbols.Labels.TryGetValue(absolute, out var label) ? label : "$" + Dump_ByteValue(absolute);
|
||||||
}
|
|
||||||
|
|
||||||
private string ConvertAddress(byte absolute)
|
private string ConvertConstant(ushort constant) => this.symbols.Constants.TryGetValue(constant, out var label) ? label : this.Dump_DByte(constant);
|
||||||
{
|
|
||||||
if (this.symbols.Labels.TryGetValue(absolute, out string label))
|
|
||||||
{
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "$" + Dump_ByteValue(absolute);
|
private string ConvertConstant(byte constant) => this.symbols.Constants.TryGetValue(constant, out var label) ? label : Dump_ByteValue(constant);
|
||||||
}
|
|
||||||
|
|
||||||
private string ConvertConstant(ushort constant)
|
private byte GetByte(ushort absolute) => this.bus.Peek(absolute);
|
||||||
{
|
|
||||||
if (this.symbols.Constants.TryGetValue(constant, out string label))
|
|
||||||
{
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.Dump_DByte(constant);
|
private ushort GetWord(ushort absolute) => this.processor.PeekWord(absolute).Word;
|
||||||
}
|
|
||||||
|
|
||||||
private string ConvertConstant(byte constant)
|
private string Dump_Byte(ushort absolute) => Disassembler.Dump_ByteValue(this.GetByte(absolute));
|
||||||
{
|
|
||||||
if (this.symbols.Constants.TryGetValue(constant, out string label))
|
|
||||||
{
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Dump_ByteValue(constant);
|
private string Dump_DByte(ushort absolute) => this.Dump_Byte(absolute) + " " + this.Dump_Byte(++absolute);
|
||||||
}
|
|
||||||
|
|
||||||
private byte GetByte(ushort absolute)
|
private string Dump_Word(ushort absolute) => Disassembler.Dump_WordValue(this.GetWord(absolute));
|
||||||
{
|
|
||||||
return this.bus.Peek(absolute);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ushort GetWord(ushort absolute)
|
private string Disassemble_Implied(string instruction) => "\t" + instruction;
|
||||||
{
|
|
||||||
return this.processor.PeekWord(absolute).Word;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Dump_Byte(ushort absolute)
|
private string Disassemble_Absolute(string instruction) => this.AM_Absolute_dump() + "\t" + instruction + " " + this.AM_Absolute();
|
||||||
{
|
|
||||||
return Disassembler.Dump_ByteValue(this.GetByte(absolute));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Dump_DByte(ushort absolute)
|
private string Disassemble_Indirect(string instruction) => this.AM_Absolute_dump() + "\t" + instruction + " (" + this.AM_Absolute() + ")";
|
||||||
{
|
|
||||||
return this.Dump_Byte(absolute) + " " + this.Dump_Byte(++absolute);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Dump_Word(ushort absolute)
|
private string Disassemble_Relative(string instruction, ushort absolute) => this.AM_Immediate_dump() + "\t" + instruction + " $" + Disassembler.Dump_WordValue(absolute);
|
||||||
{
|
|
||||||
return Disassembler.Dump_WordValue(this.GetWord(absolute));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_Implied(string instruction)
|
private string Disassemble_Immediate(string instruction) => this.AM_Immediate_dump() + "\t" + instruction + " " + this.AM_Immediate();
|
||||||
{
|
|
||||||
return "\t" + instruction;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_Absolute(string instruction)
|
private string Disassemble_AM_00(int bbb, string instruction) => this.AM_00_dump(bbb) + "\t" + instruction + " " + this.AM_00(bbb);
|
||||||
{
|
|
||||||
return this.AM_Absolute_dump() + "\t" + instruction + " " + this.AM_Absolute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_Indirect(string instruction)
|
private string Disassemble_AM_01(int bbb, string instruction) => this.AM_01_dump(bbb) + "\t" + instruction + " " + this.AM_01(bbb);
|
||||||
{
|
|
||||||
return this.AM_Absolute_dump() + "\t" + instruction + " (" + this.AM_Absolute() + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_Relative(string instruction, ushort absolute)
|
private string Disassemble_AM_10(int bbb, string instruction) => this.AM_10_dump(bbb) + "\t" + instruction + " " + this.AM_10(bbb);
|
||||||
{
|
|
||||||
return this.AM_Immediate_dump() + "\t" + instruction + " $" + Disassembler.Dump_WordValue(absolute);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_Immediate(string instruction)
|
private string Disassemble_AM_10_x(int bbb, string instruction) => this.AM_10_x_dump(bbb) + "\t" + instruction + " " + this.AM_10_x(bbb);
|
||||||
{
|
|
||||||
return this.AM_Immediate_dump() + "\t" + instruction + " " + this.AM_Immediate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_AM_00(int bbb, string instruction)
|
private string Disassemble_AM_11(int bbb, string instruction) => this.AM_11_dump(bbb) + "\t" + instruction + " " + this.AM_11(bbb);
|
||||||
{
|
|
||||||
return this.AM_00_dump(bbb) + "\t" + instruction + " " + this.AM_00(bbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_AM_01(int bbb, string instruction)
|
private string Disassemble_AM_11_x(int bbb, string instruction) => this.AM_11_x_dump(bbb) + "\t" + instruction + " " + this.AM_11_x(bbb);
|
||||||
{
|
|
||||||
return this.AM_01_dump(bbb) + "\t" + instruction + " " + this.AM_01(bbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_AM_10(int bbb, string instruction)
|
private string AM_Immediate_dump() => this.Dump_Byte((ushort)(this.address + 1));
|
||||||
{
|
|
||||||
return this.AM_10_dump(bbb) + "\t" + instruction + " " + this.AM_10(bbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_AM_10_x(int bbb, string instruction)
|
private string AM_Immediate() => "#$" + this.AM_Immediate_dump();
|
||||||
{
|
|
||||||
return this.AM_10_x_dump(bbb) + "\t" + instruction + " " + this.AM_10_x(bbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_AM_11(int bbb, string instruction)
|
private string AM_Absolute_dump() => this.Dump_DByte((ushort)(this.address + 1));
|
||||||
{
|
|
||||||
return this.AM_11_dump(bbb) + "\t" + instruction + " " + this.AM_11(bbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble_AM_11_x(int bbb, string instruction)
|
private string AM_Absolute() => "$" + this.Dump_Word((ushort)(this.address + 1));
|
||||||
{
|
|
||||||
return this.AM_11_x_dump(bbb) + "\t" + instruction + " " + this.AM_11_x(bbb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_Immediate_dump()
|
private string AM_ZeroPage_dump() => this.Dump_Byte((ushort)(this.address + 1));
|
||||||
{
|
|
||||||
return this.Dump_Byte((ushort)(this.address + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_Immediate()
|
private string AM_ZeroPage() => "$" + this.Dump_Byte((ushort)(this.address + 1));
|
||||||
{
|
|
||||||
return "#$" + this.AM_Immediate_dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_Absolute_dump()
|
private string AM_ZeroPageX_dump() => this.AM_ZeroPage_dump();
|
||||||
{
|
|
||||||
return this.Dump_DByte((ushort)(this.address + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_Absolute()
|
private string AM_ZeroPageX() => this.AM_ZeroPage() + ",X";
|
||||||
{
|
|
||||||
return "$" + this.Dump_Word((ushort)(this.address + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_ZeroPage_dump()
|
private string AM_ZeroPageY_dump() => this.AM_ZeroPage_dump();
|
||||||
{
|
|
||||||
return this.Dump_Byte((ushort)(this.address + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_ZeroPage()
|
private string AM_ZeroPageY() => this.AM_ZeroPage() + ",Y";
|
||||||
{
|
|
||||||
return "$" + this.Dump_Byte((ushort)(this.address + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_ZeroPageX_dump()
|
private string AM_AbsoluteX_dump() => this.AM_Absolute_dump();
|
||||||
{
|
|
||||||
return this.AM_ZeroPage_dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_ZeroPageX()
|
private string AM_AbsoluteX() => this.AM_Absolute() + ",X";
|
||||||
{
|
|
||||||
return this.AM_ZeroPage() + ",X";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_ZeroPageY_dump()
|
private string AM_AbsoluteY_dump() => this.AM_Absolute_dump();
|
||||||
{
|
|
||||||
return this.AM_ZeroPage_dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_ZeroPageY()
|
private string AM_AbsoluteY() => this.AM_Absolute() + ",Y";
|
||||||
{
|
|
||||||
return this.AM_ZeroPage() + ",Y";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_AbsoluteX_dump()
|
private string AM_IndexedIndirectX_dump() => this.AM_ZeroPage_dump();
|
||||||
{
|
|
||||||
return this.AM_Absolute_dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_AbsoluteX()
|
private string AM_IndexedIndirectX() => "($" + this.Dump_Byte((ushort)(this.address + 1)) + ",X)";
|
||||||
{
|
|
||||||
return this.AM_Absolute() + ",X";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_AbsoluteY_dump()
|
private string AM_IndirectIndexedY_dump() => this.AM_ZeroPage_dump();
|
||||||
{
|
|
||||||
return this.AM_Absolute_dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_AbsoluteY()
|
private string AM_IndirectIndexedY() => "($" + this.Dump_Byte((ushort)(this.address + 1)) + "),Y";
|
||||||
{
|
|
||||||
return this.AM_Absolute() + ",Y";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_IndexedIndirectX_dump()
|
|
||||||
{
|
|
||||||
return this.AM_ZeroPage_dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_IndexedIndirectX()
|
|
||||||
{
|
|
||||||
return "($" + this.Dump_Byte((ushort)(this.address + 1)) + ",X)";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_IndirectIndexedY_dump()
|
|
||||||
{
|
|
||||||
return this.AM_ZeroPage_dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_IndirectIndexedY()
|
|
||||||
{
|
|
||||||
return "($" + this.Dump_Byte((ushort)(this.address + 1)) + "),Y";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AM_00_dump(int bbb)
|
private string AM_00_dump(int bbb)
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,6 @@ namespace M6502.Test
|
|||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
var programFilename = this.configuration.Program;
|
|
||||||
var programPath = this.configuration.RomDirectory + "/" + this.configuration.Program;
|
var programPath = this.configuration.RomDirectory + "/" + this.configuration.Program;
|
||||||
var loadAddress = this.configuration.LoadAddress;
|
var loadAddress = this.configuration.LoadAddress;
|
||||||
this.ram.Load(programPath, loadAddress.Word);
|
this.ram.Load(programPath, loadAddress.Word);
|
||||||
@ -88,7 +87,6 @@ namespace M6502.Test
|
|||||||
private void CPU_ExecutingInstruction(object sender, System.EventArgs e)
|
private void CPU_ExecutingInstruction(object sender, System.EventArgs e)
|
||||||
{
|
{
|
||||||
var address = this.CPU.PC.Word;
|
var address = this.CPU.PC.Word;
|
||||||
var cell = this.Peek(address);
|
|
||||||
|
|
||||||
var output = new StringBuilder();
|
var output = new StringBuilder();
|
||||||
|
|
||||||
|
@ -8,28 +8,18 @@ namespace M6502.Test
|
|||||||
|
|
||||||
internal class Configuration
|
internal class Configuration
|
||||||
{
|
{
|
||||||
private readonly Register16 loadAddress = new Register16(0x400);
|
|
||||||
private readonly Register16 startAddress = new Register16(0x400);
|
|
||||||
private readonly string romDirectory = "roms";
|
|
||||||
private readonly string program = "6502_functional_test.bin";
|
|
||||||
private bool debugMode = false;
|
|
||||||
|
|
||||||
public Configuration()
|
public Configuration()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DebugMode
|
public bool DebugMode { get; set; } = false;
|
||||||
{
|
|
||||||
get => this.debugMode;
|
|
||||||
set => this.debugMode = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Register16 LoadAddress { get => this.loadAddress; }
|
public Register16 LoadAddress { get; } = new Register16(0x400);
|
||||||
|
|
||||||
public Register16 StartAddress { get => this.startAddress; }
|
public Register16 StartAddress { get; } = new Register16(0x400);
|
||||||
|
|
||||||
public string RomDirectory { get => this.romDirectory; }
|
public string RomDirectory { get; } = "roms";
|
||||||
|
|
||||||
public string Program { get => this.program; }
|
public string Program { get; } = "6502_functional_test.bin";
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,14 +12,10 @@ namespace M6502.Test
|
|||||||
private readonly Stopwatch timer = new Stopwatch();
|
private readonly Stopwatch timer = new Stopwatch();
|
||||||
private readonly Board board;
|
private readonly Board board;
|
||||||
private long totalCycles = 0;
|
private long totalCycles = 0;
|
||||||
private long instructions = 0;
|
|
||||||
|
|
||||||
private bool disposed = false;
|
private bool disposed = false;
|
||||||
|
|
||||||
public TestHarness(Configuration configuration)
|
public TestHarness(Configuration configuration) => this.board = new Board(configuration);
|
||||||
{
|
|
||||||
this.board = new Board(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@ -38,7 +34,6 @@ namespace M6502.Test
|
|||||||
while (cpu.Powered)
|
while (cpu.Powered)
|
||||||
{
|
{
|
||||||
this.totalCycles += cpu.Step();
|
this.totalCycles += cpu.Step();
|
||||||
++this.instructions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.timer.Stop();
|
this.timer.Stop();
|
||||||
|
@ -555,8 +555,6 @@ namespace EightBit
|
|||||||
|
|
||||||
private static byte ClearFlag(byte f, StatusBits flag, int condition) => ClearFlag(f, (byte)flag, condition);
|
private static byte ClearFlag(byte f, StatusBits flag, int condition) => ClearFlag(f, (byte)flag, condition);
|
||||||
|
|
||||||
private static byte ClearFlag(byte f, StatusBits flag, bool condition) => ClearFlag(f, (byte)flag, condition);
|
|
||||||
|
|
||||||
private void HandleNMI()
|
private void HandleNMI()
|
||||||
{
|
{
|
||||||
this.RaiseNMI();
|
this.RaiseNMI();
|
||||||
@ -769,10 +767,7 @@ namespace EightBit
|
|||||||
return returned;
|
return returned;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte SUB(byte operand, byte data, int borrow = 0)
|
private byte SUB(byte operand, byte data, int borrow = 0) => this.Decimal != 0 ? this.SUB_d(operand, data, borrow) : this.SUB_b(operand, data, borrow);
|
||||||
{
|
|
||||||
return this.Decimal != 0 ? this.SUB_d(operand, data, borrow) : this.SUB_b(operand, data, borrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte SUB_b(byte operand, byte data, int borrow)
|
private byte SUB_b(byte operand, byte data, int borrow)
|
||||||
{
|
{
|
||||||
@ -808,10 +803,7 @@ namespace EightBit
|
|||||||
return returned;
|
return returned;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte ADD(byte operand, byte data, int carry = 0)
|
private byte ADD(byte operand, byte data, int carry = 0) => this.Decimal != 0 ? this.ADD_d(operand, data, carry) : this.ADD_b(operand, data, carry);
|
||||||
{
|
|
||||||
return this.Decimal != 0 ? this.ADD_d(operand, data, carry) : this.ADD_b(operand, data, carry);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte ADD_b(byte operand, byte data, int carry)
|
private byte ADD_b(byte operand, byte data, int carry)
|
||||||
{
|
{
|
||||||
|
@ -4,29 +4,21 @@
|
|||||||
|
|
||||||
namespace EightBit
|
namespace EightBit
|
||||||
{
|
{
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
public class Disassembler
|
public class Disassembler
|
||||||
{
|
{
|
||||||
private readonly 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)
|
public Disassembler(Bus bus) => this.Bus = bus;
|
||||||
{
|
|
||||||
this.bus = bus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bus Bus => this.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 : "-";
|
||||||
|
|
||||||
public static string AsFlags(byte value)
|
public static string AsFlags(byte value) =>
|
||||||
{
|
$"{AsFlag(value, StatusBits.SF, "S")}"
|
||||||
return $"{AsFlag(value, StatusBits.SF, "S")}"
|
|
||||||
+ $"{AsFlag(value, StatusBits.ZF, "Z")}"
|
+ $"{AsFlag(value, StatusBits.ZF, "Z")}"
|
||||||
+ $"{AsFlag(value, StatusBits.YF, "Y")}"
|
+ $"{AsFlag(value, StatusBits.YF, "Y")}"
|
||||||
+ $"{AsFlag(value, StatusBits.HC, "H")}"
|
+ $"{AsFlag(value, StatusBits.HC, "H")}"
|
||||||
@ -34,7 +26,6 @@ namespace EightBit
|
|||||||
+ $"{AsFlag(value, StatusBits.PF, "P")}"
|
+ $"{AsFlag(value, StatusBits.PF, "P")}"
|
||||||
+ $"{AsFlag(value, StatusBits.NF, "N")}"
|
+ $"{AsFlag(value, StatusBits.NF, "N")}"
|
||||||
+ $"{AsFlag(value, StatusBits.CF, "C")}";
|
+ $"{AsFlag(value, StatusBits.CF, "C")}";
|
||||||
}
|
|
||||||
|
|
||||||
public static string State(Z80 cpu)
|
public static string State(Z80 cpu)
|
||||||
{
|
{
|
||||||
@ -147,10 +138,10 @@ namespace EightBit
|
|||||||
|
|
||||||
var output = $"{opCode:x2}";
|
var output = $"{opCode:x2}";
|
||||||
|
|
||||||
string specification = string.Empty;
|
var specification = string.Empty;
|
||||||
if (this.prefixCB)
|
if (this.prefixCB)
|
||||||
{
|
{
|
||||||
output += this.DisassembleCB(cpu, pc, ref specification, ref dumpCount, x, y, z, p, q);
|
output += this.DisassembleCB(ref specification, x, y, z);
|
||||||
}
|
}
|
||||||
else if (this.prefixED)
|
else if (this.prefixED)
|
||||||
{
|
{
|
||||||
@ -161,7 +152,7 @@ namespace EightBit
|
|||||||
output += this.DisassembleOther(cpu, pc, ref specification, ref dumpCount, x, y, z, p, q);
|
output += this.DisassembleOther(cpu, pc, ref specification, ref dumpCount, x, y, z, p, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < dumpCount; ++i)
|
for (var i = 0; i < dumpCount; ++i)
|
||||||
{
|
{
|
||||||
output += $"{this.Bus.Peek((ushort)(pc + i + 1)):x2}";
|
output += $"{this.Bus.Peek((ushort)(pc + i + 1)):x2}";
|
||||||
}
|
}
|
||||||
@ -184,9 +175,9 @@ namespace EightBit
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string DisassembleCB(Z80 cpu, ushort pc, ref string specification, ref int dumpCount, int x, int y, int z, int p, int q)
|
private string DisassembleCB(ref string specification, int x, int y, int z)
|
||||||
{
|
{
|
||||||
string output = string.Empty;
|
var output = string.Empty;
|
||||||
switch (x)
|
switch (x)
|
||||||
{
|
{
|
||||||
case 0: // rot[y] r[z]
|
case 0: // rot[y] r[z]
|
||||||
|
@ -15,15 +15,9 @@ namespace EightBit
|
|||||||
this.variable = (byte)(value & (byte)Mask.Mask7);
|
this.variable = (byte)(value & (byte)Mask.Mask7);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator byte(RefreshRegister input)
|
public static implicit operator byte(RefreshRegister input) => ToByte(input);
|
||||||
{
|
|
||||||
return ToByte(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator RefreshRegister(byte input)
|
public static implicit operator RefreshRegister(byte input) => FromByte(input);
|
||||||
{
|
|
||||||
return FromByte(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RefreshRegister operator ++(RefreshRegister value) => Increment(value);
|
public static RefreshRegister operator ++(RefreshRegister value) => Increment(value);
|
||||||
|
|
||||||
@ -31,10 +25,7 @@ namespace EightBit
|
|||||||
|
|
||||||
public static bool operator !=(RefreshRegister left, RefreshRegister right) => !(left == right);
|
public static bool operator !=(RefreshRegister left, RefreshRegister right) => !(left == right);
|
||||||
|
|
||||||
public static byte ToByte(RefreshRegister input)
|
public static byte ToByte(RefreshRegister input) => (byte)((input.high << 7) | (input.variable & (byte)Mask.Mask7));
|
||||||
{
|
|
||||||
return (byte)((input.high << 7) | (input.variable & (byte)Mask.Mask7));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RefreshRegister Increment(RefreshRegister value)
|
public static RefreshRegister Increment(RefreshRegister value)
|
||||||
{
|
{
|
||||||
@ -42,15 +33,9 @@ namespace EightBit
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RefreshRegister FromByte(byte input)
|
public static RefreshRegister FromByte(byte input) => new RefreshRegister(input);
|
||||||
{
|
|
||||||
return new RefreshRegister(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte ToByte()
|
public byte ToByte() => ToByte(this);
|
||||||
{
|
|
||||||
return ToByte(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +46,6 @@ namespace Z80.Test
|
|||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
var programFilename = this.configuration.Program;
|
|
||||||
var programPath = this.configuration.RomDirectory + "/" + this.configuration.Program;
|
var programPath = this.configuration.RomDirectory + "/" + this.configuration.Program;
|
||||||
var loadAddress = this.configuration.LoadAddress;
|
var loadAddress = this.configuration.LoadAddress;
|
||||||
this.ram.Load(programPath, loadAddress.Word);
|
this.ram.Load(programPath, loadAddress.Word);
|
||||||
@ -68,15 +67,15 @@ namespace Z80.Test
|
|||||||
|
|
||||||
private void BDOS()
|
private void BDOS()
|
||||||
{
|
{
|
||||||
switch (CPU.C)
|
switch (this.CPU.C)
|
||||||
{
|
{
|
||||||
case 0x2:
|
case 0x2:
|
||||||
System.Console.Out.Write(CPU.E.ToString());
|
System.Console.Out.Write(this.CPU.E.ToString());
|
||||||
break;
|
break;
|
||||||
case 0x9:
|
case 0x9:
|
||||||
for (ushort i = CPU.DE.Word; Peek(i) != '$'; ++i)
|
for (var i = this.CPU.DE.Word; this.Peek(i) != '$'; ++i)
|
||||||
{
|
{
|
||||||
System.Console.Out.Write((char)Peek(i));
|
System.Console.Out.Write((char)this.Peek(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -95,21 +94,15 @@ namespace Z80.Test
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 0x5: // BDOS
|
case 0x5: // BDOS
|
||||||
BDOS();
|
this.BDOS();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CPU_LoweredHALT(object sender, System.EventArgs e)
|
private void CPU_LoweredHALT(object sender, System.EventArgs e) => this.LowerPOWER();
|
||||||
{
|
|
||||||
this.LowerPOWER();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CPU_ExecutingInstruction_Debug(object sender, System.EventArgs e)
|
private void CPU_ExecutingInstruction_Debug(object sender, System.EventArgs e) => System.Console.Error.WriteLine($"{EightBit.Disassembler.State(this.CPU)}\t{this.disassembler.Disassemble(this.CPU)}");
|
||||||
{
|
|
||||||
System.Console.Error.WriteLine($"{EightBit.Disassembler.State(this.CPU)}\t{this.disassembler.Disassemble(this.CPU)}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ namespace Z80.Test
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
configuration.DebugMode = true;
|
configuration.DebugMode = true;
|
||||||
#endif
|
#endif
|
||||||
// configuration.DebugMode = true;
|
|
||||||
|
|
||||||
using (var harness = new TestHarness(configuration))
|
using (var harness = new TestHarness(configuration))
|
||||||
{
|
{
|
||||||
|
@ -12,14 +12,10 @@ namespace Z80.Test
|
|||||||
private readonly Stopwatch timer = new Stopwatch();
|
private readonly Stopwatch timer = new Stopwatch();
|
||||||
private readonly Board board;
|
private readonly Board board;
|
||||||
private long totalCycles = 0;
|
private long totalCycles = 0;
|
||||||
private long instructions = 0;
|
|
||||||
|
|
||||||
private bool disposed = false;
|
private bool disposed = false;
|
||||||
|
|
||||||
public TestHarness(Configuration configuration)
|
public TestHarness(Configuration configuration) => this.board = new Board(configuration);
|
||||||
{
|
|
||||||
this.board = new Board(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@ -38,7 +34,6 @@ namespace Z80.Test
|
|||||||
while (cpu.Powered)
|
while (cpu.Powered)
|
||||||
{
|
{
|
||||||
this.totalCycles += cpu.Step();
|
this.totalCycles += cpu.Step();
|
||||||
++this.instructions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.timer.Stop();
|
this.timer.Stop();
|
||||||
|
83
Z80/Z80.cs
83
Z80/Z80.cs
@ -28,7 +28,6 @@ namespace EightBit
|
|||||||
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 PinLevel nmiLine = PinLevel.Low;
|
private PinLevel nmiLine = PinLevel.Low;
|
||||||
private PinLevel m1Line = PinLevel.Low;
|
private PinLevel m1Line = PinLevel.Low;
|
||||||
@ -40,10 +39,7 @@ namespace EightBit
|
|||||||
private bool displaced = false;
|
private bool displaced = false;
|
||||||
|
|
||||||
public Z80(Bus bus, InputOutput ports)
|
public Z80(Bus bus, InputOutput ports)
|
||||||
: base(bus)
|
: base(bus) => this.ports = ports;
|
||||||
{
|
|
||||||
this.ports = ports;
|
|
||||||
}
|
|
||||||
|
|
||||||
public event EventHandler<EventArgs> ExecutingInstruction;
|
public event EventHandler<EventArgs> ExecutingInstruction;
|
||||||
|
|
||||||
@ -130,7 +126,7 @@ namespace EightBit
|
|||||||
this.Exx();
|
this.Exx();
|
||||||
this.IX.Word = this.IY.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16;
|
this.IX.Word = this.IY.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16;
|
||||||
|
|
||||||
this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
|
this.prefixCB = this.prefixDD = this.prefixED = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void RaiseNMI()
|
public virtual void RaiseNMI()
|
||||||
@ -204,7 +200,7 @@ namespace EightBit
|
|||||||
this.OnExecutingInstruction();
|
this.OnExecutingInstruction();
|
||||||
if (this.Powered)
|
if (this.Powered)
|
||||||
{
|
{
|
||||||
this.displaced = this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
|
this.displaced = this.prefixCB = this.prefixDD = this.prefixED = false;
|
||||||
this.LowerM1();
|
this.LowerM1();
|
||||||
if (this.RESET().Lowered())
|
if (this.RESET().Lowered())
|
||||||
{
|
{
|
||||||
@ -295,22 +291,11 @@ namespace EightBit
|
|||||||
|
|
||||||
private static byte ClearFlag(byte f, StatusBits flag, int condition) => ClearFlag(f, (byte)flag, condition);
|
private static byte ClearFlag(byte f, StatusBits flag, int condition) => ClearFlag(f, (byte)flag, condition);
|
||||||
|
|
||||||
private static byte ClearFlag(byte f, StatusBits flag, bool condition) => ClearFlag(f, (byte)flag, condition);
|
private static byte AdjustSign(byte input, byte value) => SetFlag(input, StatusBits.SF, value & (byte)StatusBits.SF);
|
||||||
|
|
||||||
private static byte AdjustSign(byte input, byte value)
|
private static byte AdjustZero(byte input, byte value) => ClearFlag(input, StatusBits.ZF, value);
|
||||||
{
|
|
||||||
return SetFlag(input, StatusBits.SF, value & (byte)StatusBits.SF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte AdjustZero(byte input, byte value)
|
private static byte AdjustParity(byte input, byte value) => SetFlag(input, StatusBits.PF, EvenParity(value));
|
||||||
{
|
|
||||||
return ClearFlag(input, StatusBits.ZF, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte AdjustParity(byte input, byte value)
|
|
||||||
{
|
|
||||||
return SetFlag(input, StatusBits.PF, EvenParity(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte AdjustSZ(byte input, byte value)
|
private static byte AdjustSZ(byte input, byte value)
|
||||||
{
|
{
|
||||||
@ -342,15 +327,9 @@ namespace EightBit
|
|||||||
return AdjustXY(input, value);
|
return AdjustXY(input, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte AdjustHalfCarryAdd(byte input, byte before, byte value, int calculation)
|
private static byte AdjustHalfCarryAdd(byte input, byte before, byte value, int calculation) => SetFlag(input, StatusBits.HC, CalculateHalfCarryAdd(before, value, calculation));
|
||||||
{
|
|
||||||
return SetFlag(input, StatusBits.HC, CalculateHalfCarryAdd(before, value, calculation));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte AdjustHalfCarrySub(byte input, byte before, byte value, int calculation)
|
private static byte AdjustHalfCarrySub(byte input, byte before, byte value, int calculation) => SetFlag(input, StatusBits.HC, CalculateHalfCarrySub(before, value, calculation));
|
||||||
{
|
|
||||||
return SetFlag(input, StatusBits.HC, CalculateHalfCarrySub(before, value, calculation));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte AdjustOverflowAdd(byte input, int beforeNegative, int valueNegative, int afterNegative)
|
private static byte AdjustOverflowAdd(byte input, int beforeNegative, int valueNegative, int afterNegative)
|
||||||
{
|
{
|
||||||
@ -358,10 +337,7 @@ namespace EightBit
|
|||||||
return SetFlag(input, StatusBits.VF, overflow);
|
return SetFlag(input, StatusBits.VF, overflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte AdjustOverflowAdd(byte input, byte before, byte value, byte calculation)
|
private static byte AdjustOverflowAdd(byte input, byte before, byte value, byte calculation) => AdjustOverflowAdd(input, before & (byte)StatusBits.SF, value & (byte)StatusBits.SF, calculation & (byte)StatusBits.SF);
|
||||||
{
|
|
||||||
return AdjustOverflowAdd(input, before & (byte)StatusBits.SF, value & (byte)StatusBits.SF, calculation & (byte)StatusBits.SF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte AdjustOverflowSub(byte input, int beforeNegative, int valueNegative, int afterNegative)
|
private static byte AdjustOverflowSub(byte input, int beforeNegative, int valueNegative, int afterNegative)
|
||||||
{
|
{
|
||||||
@ -369,20 +345,11 @@ namespace EightBit
|
|||||||
return SetFlag(input, StatusBits.VF, overflow);
|
return SetFlag(input, StatusBits.VF, overflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte AdjustOverflowSub(byte input, byte before, byte value, byte calculation)
|
private static byte AdjustOverflowSub(byte input, byte before, byte value, byte calculation) => AdjustOverflowSub(input, before & (byte)StatusBits.SF, value & (byte)StatusBits.SF, calculation & (byte)StatusBits.SF);
|
||||||
{
|
|
||||||
return AdjustOverflowSub(input, before & (byte)StatusBits.SF, value & (byte)StatusBits.SF, calculation & (byte)StatusBits.SF);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte RES(int n, byte operand)
|
private static byte RES(int n, byte operand) => (byte)(operand & ~(1 << n));
|
||||||
{
|
|
||||||
return (byte)(operand & ~(1 << n));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte SET(int n, byte operand)
|
private static byte SET(int n, byte operand) => (byte)(operand | (1 << n));
|
||||||
{
|
|
||||||
return (byte)(operand | (1 << n));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DisableInterrupts() => this.IFF1 = this.IFF2 = false;
|
private void DisableInterrupts() => this.IFF1 = this.IFF2 = false;
|
||||||
|
|
||||||
@ -531,7 +498,6 @@ namespace EightBit
|
|||||||
|
|
||||||
private void ExecuteCB(int x, int y, int z)
|
private void ExecuteCB(int x, int y, int z)
|
||||||
{
|
{
|
||||||
var memoryY = y == 6;
|
|
||||||
var memoryZ = z == 6;
|
var memoryZ = z == 6;
|
||||||
var indirect = (!this.displaced && memoryZ) || this.displaced;
|
var indirect = (!this.displaced && memoryZ) || this.displaced;
|
||||||
var direct = !indirect;
|
var direct = !indirect;
|
||||||
@ -620,8 +586,6 @@ namespace EightBit
|
|||||||
|
|
||||||
private void ExecuteED(int x, int y, int z, int p, int q)
|
private void ExecuteED(int x, int y, int z, int p, int q)
|
||||||
{
|
{
|
||||||
var memoryY = y == 6;
|
|
||||||
var memoryZ = z == 6;
|
|
||||||
switch (x)
|
switch (x)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@ -647,14 +611,7 @@ namespace EightBit
|
|||||||
case 1: // Output to port with 16-bit address
|
case 1: // Output to port with 16-bit address
|
||||||
this.MEMPTR.Word = this.Bus.Address.Word = this.BC.Word;
|
this.MEMPTR.Word = this.Bus.Address.Word = this.BC.Word;
|
||||||
this.MEMPTR.Word++;
|
this.MEMPTR.Word++;
|
||||||
if (y != 6)
|
this.Bus.Data = y != 6 ? this.R(y) : (byte)0;
|
||||||
{
|
|
||||||
this.Bus.Data = this.R(y); // OUT (C),r[y]
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.Bus.Data = 0; // OUT (C),0
|
|
||||||
}
|
|
||||||
|
|
||||||
this.WritePort();
|
this.WritePort();
|
||||||
this.Tick(12);
|
this.Tick(12);
|
||||||
@ -1132,7 +1089,7 @@ namespace EightBit
|
|||||||
case 1: // 8-bit loading
|
case 1: // 8-bit loading
|
||||||
if (!(memoryZ && memoryY))
|
if (!(memoryZ && memoryY))
|
||||||
{
|
{
|
||||||
bool normal = true;
|
var normal = true;
|
||||||
if (this.displaced)
|
if (this.displaced)
|
||||||
{
|
{
|
||||||
if (memoryZ || memoryY)
|
if (memoryZ || memoryY)
|
||||||
@ -1365,7 +1322,7 @@ namespace EightBit
|
|||||||
this.Execute(this.FetchByte());
|
this.Execute(this.FetchByte());
|
||||||
break;
|
break;
|
||||||
case 3: // FD prefix
|
case 3: // FD prefix
|
||||||
this.displaced = this.prefixFD = true;
|
this.displaced = true;
|
||||||
this.LowerM1();
|
this.LowerM1();
|
||||||
this.Execute(this.FetchByte());
|
this.Execute(this.FetchByte());
|
||||||
break;
|
break;
|
||||||
@ -2038,10 +1995,7 @@ namespace EightBit
|
|||||||
++this.MEMPTR.Low;
|
++this.MEMPTR.Low;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WritePort()
|
private void WritePort() => this.ports.Write(this.Bus.Address.Low, this.Bus.Data);
|
||||||
{
|
|
||||||
this.ports.Write(this.Bus.Address.Low, this.Bus.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte ReadPort(byte port)
|
private byte ReadPort(byte port)
|
||||||
{
|
{
|
||||||
@ -2050,9 +2004,6 @@ namespace EightBit
|
|||||||
return this.ReadPort();
|
return this.ReadPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte ReadPort()
|
private byte ReadPort() => this.Bus.Data = this.ports.Read(this.Bus.Address.Low);
|
||||||
{
|
|
||||||
return this.Bus.Data = this.ports.Read(this.Bus.Address.Low);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user