mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2024-06-11 15:29:37 +00:00
Apply any analysis suggestions.
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
parent
73d08fe7a7
commit
2becf0e220
|
@ -66,8 +66,8 @@ namespace EightBit
|
||||||
public void Write()
|
public void Write()
|
||||||
{
|
{
|
||||||
this.OnWritingByte();
|
this.OnWritingByte();
|
||||||
var data = this.Data; // N.B. Don't join these two lines together: the
|
var value = this.Data; // N.B. Don't join these two lines together: the
|
||||||
this.Reference() = data; // data bus integrity is lost, due to evaluation order!
|
this.Reference() = value; // data bus integrity is lost, due to evaluation order!
|
||||||
this.OnWrittenByte();
|
this.OnWrittenByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
namespace EightBit
|
namespace EightBit
|
||||||
{
|
{
|
||||||
|
using System;
|
||||||
|
|
||||||
public class Disassembler
|
public class Disassembler
|
||||||
{
|
{
|
||||||
private bool prefixCB = false;
|
private bool prefixCB = false;
|
||||||
|
@ -29,6 +31,11 @@ namespace EightBit
|
||||||
|
|
||||||
public static string State(Z80 cpu)
|
public static string State(Z80 cpu)
|
||||||
{
|
{
|
||||||
|
if (cpu == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(cpu));
|
||||||
|
}
|
||||||
|
|
||||||
var pc = cpu.PC;
|
var pc = cpu.PC;
|
||||||
var sp = cpu.SP;
|
var sp = cpu.SP;
|
||||||
|
|
||||||
|
@ -68,59 +75,40 @@ namespace EightBit
|
||||||
|
|
||||||
public string Disassemble(Z80 cpu)
|
public string Disassemble(Z80 cpu)
|
||||||
{
|
{
|
||||||
|
if (cpu == null)
|
||||||
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string CC(int flag)
|
private static string CC(int flag) => flag switch
|
||||||
{
|
{
|
||||||
switch (flag)
|
0 => "NZ",
|
||||||
{
|
1 => "Z",
|
||||||
case 0:
|
2 => "NC",
|
||||||
return "NZ";
|
3 => "C",
|
||||||
case 1:
|
4 => "PO",
|
||||||
return "Z";
|
5 => "PE",
|
||||||
case 2:
|
6 => "P",
|
||||||
return "NC";
|
7 => "M",
|
||||||
case 3:
|
_ => throw new System.ArgumentOutOfRangeException(nameof(flag)),
|
||||||
return "C";
|
};
|
||||||
case 4:
|
|
||||||
return "PO";
|
|
||||||
case 5:
|
|
||||||
return "PE";
|
|
||||||
case 6:
|
|
||||||
return "P";
|
|
||||||
case 7:
|
|
||||||
return "M";
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new System.ArgumentOutOfRangeException(nameof(flag));
|
private static string ALU(int which) => which switch
|
||||||
}
|
|
||||||
|
|
||||||
private static string ALU(int which)
|
|
||||||
{
|
{
|
||||||
switch (which)
|
0 => "ADD",
|
||||||
{
|
1 => "ADC",
|
||||||
case 0: // ADD A,n
|
2 => "SUB",
|
||||||
return "ADD";
|
3 => "SBC",
|
||||||
case 1: // ADC
|
4 => "AND",
|
||||||
return "ADC";
|
5 => "XOR",
|
||||||
case 2: // SUB n
|
6 => "OR",
|
||||||
return "SUB";
|
7 => "CP",
|
||||||
case 3: // SBC A,n
|
_ => throw new System.ArgumentOutOfRangeException(nameof(which)),
|
||||||
return "SBC";
|
};
|
||||||
case 4: // AND n
|
|
||||||
return "AND";
|
|
||||||
case 5: // XOR n
|
|
||||||
return "XOR";
|
|
||||||
case 6: // OR n
|
|
||||||
return "OR";
|
|
||||||
case 7: // CP n
|
|
||||||
return "CP";
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new System.ArgumentOutOfRangeException(nameof(which));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Disassemble(Z80 cpu, ushort pc)
|
private string Disassemble(Z80 cpu, ushort pc)
|
||||||
{
|
{
|
||||||
|
@ -152,7 +140,7 @@ namespace EightBit
|
||||||
}
|
}
|
||||||
else if (this.prefixED)
|
else if (this.prefixED)
|
||||||
{
|
{
|
||||||
output += this.DisassembleED(cpu, pc, ref specification, ref dumpCount, x, y, z, p, q);
|
output += this.DisassembleED(ref specification, ref dumpCount, x, y, z, p, q);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -231,7 +219,7 @@ namespace EightBit
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string DisassembleED(Z80 cpu, ushort pc, ref string specification, ref int dumpCount, int x, int y, int z, int p, int q)
|
private string DisassembleED(ref string specification, ref int dumpCount, int x, int y, int z, int p, int q)
|
||||||
{
|
{
|
||||||
var output = string.Empty;
|
var output = string.Empty;
|
||||||
switch (x)
|
switch (x)
|
||||||
|
@ -272,15 +260,11 @@ namespace EightBit
|
||||||
specification = "NEG";
|
specification = "NEG";
|
||||||
break;
|
break;
|
||||||
case 5: // Return from interrupt
|
case 5: // Return from interrupt
|
||||||
switch (y)
|
specification = y switch
|
||||||
{
|
{
|
||||||
case 1:
|
1 => "RETI",
|
||||||
specification = "RETI";
|
_ => "RETN",
|
||||||
break;
|
};
|
||||||
default:
|
|
||||||
specification = "RETN";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 6: // Set interrupt mode
|
case 6: // Set interrupt mode
|
||||||
switch (y)
|
switch (y)
|
||||||
|
@ -572,15 +556,7 @@ namespace EightBit
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 1: // 8-bit loading
|
case 1: // 8-bit loading
|
||||||
if (z == 6 && y == 6)
|
specification = z == 6 && y == 6 ? "HALT" : $"LD {this.R(y)},{this.R(z)}";
|
||||||
{
|
|
||||||
specification = "HALT"; // Exception (replaces LD (HL), (HL))
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
specification = $"LD {this.R(y)},{this.R(z)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 2: // Operate on accumulator and register/memory location
|
case 2: // Operate on accumulator and register/memory location
|
||||||
specification = $"{ALU(y)} A,{this.R(z)}";
|
specification = $"{ALU(y)} A,{this.R(z)}";
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
namespace EightBit
|
namespace EightBit
|
||||||
{
|
{
|
||||||
public struct RefreshRegister
|
public struct RefreshRegister : System.IEquatable<RefreshRegister>
|
||||||
{
|
{
|
||||||
private readonly byte high;
|
private readonly byte high;
|
||||||
private byte variable;
|
private byte variable;
|
||||||
|
@ -37,17 +37,10 @@ namespace EightBit
|
||||||
|
|
||||||
public byte ToByte() => ToByte(this);
|
public byte ToByte() => ToByte(this);
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj) => obj is RefreshRegister ? this.Equals((RefreshRegister)obj) : false;
|
||||||
{
|
|
||||||
if (!(obj is RefreshRegister))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rhs = (RefreshRegister)obj;
|
|
||||||
return rhs.high == this.high && rhs.variable == this.variable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode() => this.high + this.variable;
|
public override int GetHashCode() => this.high + this.variable;
|
||||||
|
|
||||||
|
public bool Equals(RefreshRegister other) => other.high == this.high && other.variable == this.variable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
178
Z80/Z80.cs
178
Z80/Z80.cs
|
@ -28,6 +28,7 @@ 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;
|
||||||
|
@ -351,7 +352,7 @@ namespace EightBit
|
||||||
this.OnExecutingInstruction();
|
this.OnExecutingInstruction();
|
||||||
if (this.Powered)
|
if (this.Powered)
|
||||||
{
|
{
|
||||||
this.displaced = this.prefixCB = this.prefixDD = this.prefixED = false;
|
this.displaced = this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
|
||||||
var handled = false;
|
var handled = false;
|
||||||
if (this.RESET.Lowered())
|
if (this.RESET.Lowered())
|
||||||
{
|
{
|
||||||
|
@ -423,7 +424,7 @@ namespace EightBit
|
||||||
|
|
||||||
this.AF.Word = this.IX.Word = this.IY.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16;
|
this.AF.Word = this.IX.Word = this.IY.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Mask16;
|
||||||
|
|
||||||
this.prefixCB = this.prefixDD = this.prefixED = false;
|
this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
|
||||||
|
|
||||||
base.OnRaisedPOWER();
|
base.OnRaisedPOWER();
|
||||||
}
|
}
|
||||||
|
@ -630,80 +631,38 @@ namespace EightBit
|
||||||
|
|
||||||
private void EnableInterrupts() => this.IFF1 = this.IFF2 = true;
|
private void EnableInterrupts() => this.IFF1 = this.IFF2 = true;
|
||||||
|
|
||||||
private Register16 HL2()
|
private Register16 HL2() => this.prefixDD ? this.IX : this.prefixFD ? this.IY : this.HL;
|
||||||
|
|
||||||
|
private Register16 RP(int rp) => rp switch
|
||||||
{
|
{
|
||||||
if (!this.displaced)
|
0 => this.BC,
|
||||||
{
|
1 => this.DE,
|
||||||
return this.HL;
|
2 => this.HL2(),
|
||||||
}
|
3 => this.SP,
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(rp)),
|
||||||
|
};
|
||||||
|
|
||||||
if (this.prefixDD)
|
private Register16 RP2(int rp) => rp switch
|
||||||
{
|
|
||||||
return this.IX;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be FD prefix
|
|
||||||
return this.IY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Register16 RP(int rp)
|
|
||||||
{
|
{
|
||||||
switch (rp)
|
0 => this.BC,
|
||||||
{
|
1 => this.DE,
|
||||||
case 0:
|
2 => this.HL2(),
|
||||||
return this.BC;
|
3 => this.AF,
|
||||||
case 1:
|
_ => throw new ArgumentOutOfRangeException(nameof(rp)),
|
||||||
return this.DE;
|
};
|
||||||
case 2:
|
|
||||||
return this.HL2();
|
|
||||||
case 3:
|
|
||||||
return this.SP;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(rp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Register16 RP2(int rp)
|
private byte R(int r) => r switch
|
||||||
{
|
{
|
||||||
switch (rp)
|
0 => this.B,
|
||||||
{
|
1 => this.C,
|
||||||
case 0:
|
2 => this.D,
|
||||||
return this.BC;
|
3 => this.E,
|
||||||
case 1:
|
4 => this.HL2().High,
|
||||||
return this.DE;
|
5 => this.HL2().Low,
|
||||||
case 2:
|
6 => this.BusRead(this.displaced ? this.DisplacedAddress : this.HL.Word),
|
||||||
return this.HL2();
|
7 => this.A,
|
||||||
case 3:
|
_ => throw new ArgumentOutOfRangeException(nameof(r)),
|
||||||
return this.AF;
|
};
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(rp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte R(int r)
|
|
||||||
{
|
|
||||||
switch (r)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return this.B;
|
|
||||||
case 1:
|
|
||||||
return this.C;
|
|
||||||
case 2:
|
|
||||||
return this.D;
|
|
||||||
case 3:
|
|
||||||
return this.E;
|
|
||||||
case 4:
|
|
||||||
return this.HL2().High;
|
|
||||||
case 5:
|
|
||||||
return this.HL2().Low;
|
|
||||||
case 6:
|
|
||||||
return this.BusRead(this.displaced ? this.DisplacedAddress : this.HL.Word);
|
|
||||||
case 7:
|
|
||||||
return this.A;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void R(int r, byte value)
|
private void R(int r, byte value)
|
||||||
{
|
{
|
||||||
|
@ -792,36 +751,18 @@ namespace EightBit
|
||||||
switch (x)
|
switch (x)
|
||||||
{
|
{
|
||||||
case 0: // rot[y] r[z]
|
case 0: // rot[y] r[z]
|
||||||
switch (y)
|
operand = y switch
|
||||||
{
|
{
|
||||||
case 0:
|
0 => this.RLC(operand),
|
||||||
operand = this.RLC(operand);
|
1 => this.RRC(operand),
|
||||||
break;
|
2 => this.RL(operand),
|
||||||
case 1:
|
3 => this.RR(operand),
|
||||||
operand = this.RRC(operand);
|
4 => this.SLA(operand),
|
||||||
break;
|
5 => this.SRA(operand),
|
||||||
case 2:
|
6 => this.SLL(operand),
|
||||||
operand = this.RL(operand);
|
7 => this.SRL(operand),
|
||||||
break;
|
_ => throw new NotSupportedException("Invalid operation mode"),
|
||||||
case 3:
|
};
|
||||||
operand = this.RR(operand);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
operand = this.SLA(operand);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
operand = this.SRA(operand);
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
operand = this.SLL(operand);
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
operand = this.SRL(operand);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException("Invalid operation mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.F = AdjustSZP(this.F, operand);
|
this.F = AdjustSZP(this.F, operand);
|
||||||
break;
|
break;
|
||||||
case 1: // BIT y, r[z]
|
case 1: // BIT y, r[z]
|
||||||
|
@ -841,11 +782,7 @@ namespace EightBit
|
||||||
if (update)
|
if (update)
|
||||||
{
|
{
|
||||||
this.Tick();
|
this.Tick();
|
||||||
if (!this.displaced)
|
if (this.displaced)
|
||||||
{
|
|
||||||
this.R(z, operand);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
this.BusWrite(operand);
|
this.BusWrite(operand);
|
||||||
if (!memoryZ)
|
if (!memoryZ)
|
||||||
|
@ -853,6 +790,10 @@ namespace EightBit
|
||||||
this.R2(z, operand);
|
this.R2(z, operand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.R(z, operand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,18 +826,12 @@ namespace EightBit
|
||||||
this.WritePort();
|
this.WritePort();
|
||||||
break;
|
break;
|
||||||
case 2: // 16-bit add/subtract with carry
|
case 2: // 16-bit add/subtract with carry
|
||||||
switch (q)
|
this.HL2().Word = q switch
|
||||||
{
|
{
|
||||||
case 0: // SBC HL, rp[p]
|
0 => this.SBC(this.HL2(), this.RP(p)), // SBC HL, rp[p]
|
||||||
this.HL2().Word = this.SBC(this.HL2(), this.RP(p));
|
1 => this.ADC(this.HL2(), this.RP(p)), // ADC HL, rp[p]
|
||||||
break;
|
_ => throw new NotSupportedException("Invalid operation mode"),
|
||||||
case 1: // ADC HL, rp[p]
|
};
|
||||||
this.HL2().Word = this.ADC(this.HL2(), this.RP(p));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException("Invalid operation mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 3: // Retrieve/store register pair from/to immediate address
|
case 3: // Retrieve/store register pair from/to immediate address
|
||||||
this.Bus.Address.Word = this.FetchWord().Word;
|
this.Bus.Address.Word = this.FetchWord().Word;
|
||||||
|
@ -1412,13 +1347,10 @@ namespace EightBit
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{ // Operate on accumulator and register/memory location
|
{ // Operate on accumulator and register/memory location
|
||||||
if (memoryZ)
|
if (memoryZ && this.displaced)
|
||||||
{
|
{
|
||||||
if (this.displaced)
|
this.FetchDisplacement();
|
||||||
{
|
this.Tick(5);
|
||||||
this.FetchDisplacement();
|
|
||||||
this.Tick(5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = this.R(z);
|
var value = this.R(z);
|
||||||
|
@ -1563,7 +1495,7 @@ namespace EightBit
|
||||||
this.Execute(this.FetchInitialOpCode());
|
this.Execute(this.FetchInitialOpCode());
|
||||||
break;
|
break;
|
||||||
case 3: // FD prefix
|
case 3: // FD prefix
|
||||||
this.displaced = true;
|
this.displaced = this.prefixFD = true;
|
||||||
this.Execute(this.FetchInitialOpCode());
|
this.Execute(this.FetchInitialOpCode());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user