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