miscellaneous fixes, especiall flags

This commit is contained in:
Adrian Conlon 2025-03-18 18:38:47 +00:00
parent 21770b2460
commit a9db2f58bd

View File

@ -11,15 +11,11 @@ namespace Z80
private readonly InputOutput _ports = 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 =
{ [
{ [new Register16(), new Register16(), new Register16()],
new Register16(), new Register16(), new Register16(), [new Register16(), new Register16(), new Register16()]
}, ];
{
new Register16(), new Register16(), new Register16(),
},
};
private RefreshRegister _refresh = new(0x7f); private RefreshRegister _refresh = new(0x7f);
@ -108,11 +104,13 @@ namespace Z80
public override Register16 AF => this._accumulatorFlags[this._accumulatorFlagsSet]; public override Register16 AF => this._accumulatorFlags[this._accumulatorFlagsSet];
public override Register16 BC => this._registers[this._registerSet, (int)RegisterIndex.IndexBC]; private Register16[] CurrentRegisterSet => this._registers[this._registerSet];
public override Register16 DE => this._registers[this._registerSet, (int)RegisterIndex.IndexDE]; public override Register16 BC => this.CurrentRegisterSet[(int)RegisterIndex.IndexBC];
public override Register16 HL => this._registers[this._registerSet, (int)RegisterIndex.IndexHL]; public override Register16 DE => this.CurrentRegisterSet[(int)RegisterIndex.IndexDE];
public override Register16 HL => this.CurrentRegisterSet[(int)RegisterIndex.IndexHL];
public Register16 IX { get; } = new(0xffff); public Register16 IX { get; } = new(0xffff);
@ -157,14 +155,10 @@ namespace Z80
public ref PinLevel WR => ref this._wrLine; public ref PinLevel WR => ref this._wrLine;
private Register16 DisplacedAddress private void DisplaceAddress()
{
get
{ {
var displacement = (this._prefixDD ? this.IX : this.IY).Word + this._displacement; var displacement = (this._prefixDD ? this.IX : this.IY).Word + this._displacement;
this.MEMPTR.Word = (ushort)displacement; this.MEMPTR.Word = (ushort)displacement;
return this.MEMPTR;
}
} }
public void Exx() => this._registerSet ^= 1; public void Exx() => this._registerSet ^= 1;
@ -397,8 +391,9 @@ namespace Z80
protected override void OnRaisedPOWER() protected override void OnRaisedPOWER()
{ {
this.RaiseM1(); this.RaiseM1();
this.RaiseMREQ(); this.RaiseRFSH();
this.RaiseIORQ(); this.RaiseIORQ();
this.RaiseMREQ();
this.RaiseRD(); this.RaiseRD();
this.RaiseWR(); this.RaiseWR();
@ -411,13 +406,19 @@ namespace Z80
this.ExxAF(); this.ExxAF();
this.Exx(); this.Exx();
this.AF.Word = this.IX.Word = this.IY.Word = this.BC.Word = this.DE.Word = this.HL.Word = (ushort)Mask.Sixteen; this.IX.Word = this.IY.Word = (ushort)Mask.Sixteen;
base.ResetWorkingRegisters();
this._prefixCB = this._prefixDD = this._prefixED = this._prefixFD = false; this.ResetPrefixes();
base.OnRaisedPOWER(); base.OnRaisedPOWER();
} }
private void ResetPrefixes()
{
this._prefixCB = this._prefixDD = this._prefixED = this._prefixFD = false;
}
protected virtual void OnRaisingNMI() => RaisingNMI?.Invoke(this, EventArgs.Empty); protected virtual void OnRaisingNMI() => RaisingNMI?.Invoke(this, EventArgs.Empty);
protected virtual void OnRaisedNMI() => RaisedNMI?.Invoke(this, EventArgs.Empty); protected virtual void OnRaisedNMI() => RaisedNMI?.Invoke(this, EventArgs.Empty);
@ -543,6 +544,76 @@ namespace Z80
base.Call(destination); base.Call(destination);
} }
private int Zero()
{
return ZeroTest(this.F);
}
private int Carry()
{
return CarryTest(this.F);
}
private int Parity()
{
return ParityTest(this.F);
}
private int Sign()
{
return SignTest(this.F);
}
private int HalfCarry()
{
return HalfCarryTest(this.F);
}
private int Subtracting()
{
return SubtractingTest(this.F);
}
private static int ZeroTest(byte data)
{
return data & (byte)StatusBits.ZF;
}
private static int CarryTest(byte data)
{
return data & (byte)StatusBits.CF;
}
private static int ParityTest(byte data)
{
return data & (byte)StatusBits.PF;
}
private static int SignTest(byte data)
{
return data & (byte)StatusBits.SF;
}
private static int HalfCarryTest(byte data)
{
return data & (byte)StatusBits.HC;
}
private static int SubtractingTest(byte data)
{
return data & (byte)StatusBits.NF;
}
private static int XTest(byte data)
{
return data & (byte)StatusBits.XF;
}
private static int YTest(byte data)
{
return data & (byte)StatusBits.YF;
}
private static byte SetBit(byte f, StatusBits flag) => SetBit(f, (byte)flag); private static byte SetBit(byte f, StatusBits flag) => SetBit(f, (byte)flag);
private static byte SetBit(byte f, StatusBits flag, int condition) => SetBit(f, (byte)flag, condition); private static byte SetBit(byte f, StatusBits flag, int condition) => SetBit(f, (byte)flag, condition);
@ -553,7 +624,7 @@ namespace Z80
private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition); private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition);
private static byte AdjustSign(byte input, byte value) => SetBit(input, StatusBits.SF, value & (byte)StatusBits.SF); private static byte AdjustSign(byte input, byte value) => SetBit(input, StatusBits.SF, SignTest(value));
private static byte AdjustZero(byte input, byte value) => ClearBit(input, StatusBits.ZF, value); private static byte AdjustZero(byte input, byte value) => ClearBit(input, StatusBits.ZF, value);
@ -573,8 +644,8 @@ namespace Z80
private static byte AdjustXY(byte input, byte value) private static byte AdjustXY(byte input, byte value)
{ {
input = SetBit(input, StatusBits.XF, value & (byte)StatusBits.XF); input = SetBit(input, StatusBits.XF, XTest(value));
return SetBit(input, StatusBits.YF, value & (byte)StatusBits.YF); return SetBit(input, StatusBits.YF, YTest(value));
} }
private static byte AdjustSZPXY(byte input, byte value) private static byte AdjustSZPXY(byte input, byte value)
@ -599,7 +670,7 @@ namespace Z80
return SetBit(input, StatusBits.VF, overflow); return SetBit(input, StatusBits.VF, overflow);
} }
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); private static byte AdjustOverflowAdd(byte input, byte before, byte value, byte calculation) => AdjustOverflowAdd(input, SignTest(before), SignTest(value), SignTest(calculation));
private static byte AdjustOverflowSub(byte input, int beforeNegative, int valueNegative, int afterNegative) private static byte AdjustOverflowSub(byte input, int beforeNegative, int valueNegative, int afterNegative)
{ {
@ -607,7 +678,7 @@ namespace Z80
return SetBit(input, StatusBits.VF, overflow); return SetBit(input, StatusBits.VF, overflow);
} }
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); private static byte AdjustOverflowSub(byte input, byte before, byte value, byte calculation) => AdjustOverflowSub(input, SignTest(before), SignTest(value), SignTest(calculation));
private static byte RES(int n, byte operand) => ClearBit(operand, Bit(n)); private static byte RES(int n, byte operand) => ClearBit(operand, Bit(n));
@ -654,7 +725,15 @@ namespace Z80
case 5: case 5:
return ref this.HL2().Low; return ref this.HL2().Low;
case 6: case 6:
this.Bus.Address.Assign(this._displaced ? this.DisplacedAddress : this.HL); if (this._displaced)
{
this.DisplaceAddress();
this.Bus.Address.Assign(this.MEMPTR);
}
else
{
this.Bus.Address.Assign(this.HL);
}
if (access == AccessLevel.ReadOnly) if (access == AccessLevel.ReadOnly)
{ {
_ = this.MemoryRead(); _ = this.MemoryRead();
@ -714,7 +793,8 @@ namespace Z80
if (this._displaced) if (this._displaced)
{ {
this.Tick(2); this.Tick(2);
operand = this.MemoryRead(this.DisplacedAddress); this.DisplaceAddress();
operand = this.MemoryRead(this.MEMPTR);
} }
else else
{ {
@ -1610,7 +1690,7 @@ namespace Z80
this.F = AdjustOverflowSub(this.F, operand, value, result); this.F = AdjustOverflowSub(this.F, operand, value, result);
this.F = SetBit(this.F, StatusBits.NF); this.F = SetBit(this.F, StatusBits.NF);
this.F = SetBit(this.F, StatusBits.CF, this.Intermediate.High & (byte)StatusBits.CF); this.F = SetBit(this.F, StatusBits.CF, CarryTest(this.Intermediate.High));
this.F = AdjustSZ(this.F, result); this.F = AdjustSZ(this.F, result);
return result; return result;
@ -1646,14 +1726,14 @@ namespace Z80
private bool ConvertCondition(int flag) => flag switch private bool ConvertCondition(int flag) => flag switch
{ {
0 => (this.F & (byte)StatusBits.ZF) == 0, 0 => this.Zero() == 0,
1 => (this.F & (byte)StatusBits.ZF) != 0, 1 => this.Zero() != 0,
2 => (this.F & (byte)StatusBits.CF) == 0, 2 => this.Carry() == 0,
3 => (this.F & (byte)StatusBits.CF) != 0, 3 => this.Carry() != 0,
4 => (this.F & (byte)StatusBits.PF) == 0, 4 => this.Parity() == 0,
5 => (this.F & (byte)StatusBits.PF) != 0, 5 => this.Parity() != 0,
6 => (this.F & (byte)StatusBits.SF) == 0, 6 => this.Sign() == 0,
7 => (this.F & (byte)StatusBits.SF) != 0, 7 => this.Sign() != 0,
_ => throw new ArgumentOutOfRangeException(nameof(flag)), _ => throw new ArgumentOutOfRangeException(nameof(flag)),
}; };
@ -1674,7 +1754,7 @@ namespace Z80
private Register16 SBC(Register16 operand, Register16 value) private Register16 SBC(Register16 operand, Register16 value)
{ {
var subtraction = operand.Word - value.Word - (this.F & (byte)StatusBits.CF); var subtraction = operand.Word - value.Word - this.Carry();
this.Intermediate.Word = (ushort)subtraction; this.Intermediate.Word = (ushort)subtraction;
this.F = SetBit(this.F, StatusBits.NF); this.F = SetBit(this.F, StatusBits.NF);
@ -1683,9 +1763,9 @@ namespace Z80
this.F = AdjustHalfCarrySub(this.F, operand.High, value.High, this.Intermediate.High); this.F = AdjustHalfCarrySub(this.F, operand.High, value.High, this.Intermediate.High);
this.F = AdjustXY(this.F, this.Intermediate.High); this.F = AdjustXY(this.F, this.Intermediate.High);
var beforeNegative = operand.High & (byte)StatusBits.SF; var beforeNegative = SignTest(operand.High);
var valueNegative = value.High & (byte)StatusBits.SF; var valueNegative = SignTest(value.High);
var afterNegative = this.Intermediate.High & (byte)StatusBits.SF; var afterNegative = SignTest(this.Intermediate.High);
this.F = SetBit(this.F, StatusBits.SF, afterNegative); this.F = SetBit(this.F, StatusBits.SF, afterNegative);
this.F = AdjustOverflowSub(this.F, beforeNegative, valueNegative, afterNegative); this.F = AdjustOverflowSub(this.F, beforeNegative, valueNegative, afterNegative);
@ -1697,12 +1777,12 @@ namespace Z80
private Register16 ADC(Register16 operand, Register16 value) private Register16 ADC(Register16 operand, Register16 value)
{ {
_ = this.Add(operand, value, this.F & (byte)StatusBits.CF); _ = this.Add(operand, value, this.Carry());
this.F = ClearBit(this.F, StatusBits.ZF, this.Intermediate.Word); this.F = ClearBit(this.F, StatusBits.ZF, this.Intermediate.Word);
var beforeNegative = operand.High & (byte)StatusBits.SF; var beforeNegative = SignTest(operand.High);
var valueNegative = value.High & (byte)StatusBits.SF; var valueNegative = SignTest(value.High);
var afterNegative = this.Intermediate.High & (byte)StatusBits.SF; var afterNegative = SignTest(this.Intermediate.High);
this.F = SetBit(this.F, StatusBits.SF, afterNegative); this.F = SetBit(this.F, StatusBits.SF, afterNegative);
this.F = AdjustOverflowAdd(this.F, beforeNegative, valueNegative, afterNegative); this.F = AdjustOverflowAdd(this.F, beforeNegative, valueNegative, afterNegative);
@ -1734,13 +1814,13 @@ namespace Z80
this.F = AdjustOverflowAdd(this.F, operand, value, result); this.F = AdjustOverflowAdd(this.F, operand, value, result);
this.F = ClearBit(this.F, StatusBits.NF); this.F = ClearBit(this.F, StatusBits.NF);
this.F = SetBit(this.F, StatusBits.CF, this.Intermediate.High & (byte)StatusBits.CF); this.F = SetBit(this.F, StatusBits.CF, CarryTest(this.Intermediate.High));
this.F = AdjustSZXY(this.F, result); this.F = AdjustSZXY(this.F, result);
return result; return result;
} }
private byte ADC(byte operand, byte value) => this.Add(operand, value, this.F & (byte)StatusBits.CF); private byte ADC(byte operand, byte value) => this.Add(operand, value, this.Carry());
private byte SUB(byte operand, byte value, int carry = 0) private byte SUB(byte operand, byte value, int carry = 0)
{ {
@ -1749,7 +1829,7 @@ namespace Z80
return subtraction; return subtraction;
} }
private byte SBC(byte operand, byte value) => this.SUB(operand, value, this.F & (byte)StatusBits.CF); private byte SBC(byte operand, byte value) => this.SUB(operand, value, this.Carry());
private void AndR(byte value) private void AndR(byte value)
{ {
@ -1799,7 +1879,7 @@ namespace Z80
private byte RL(byte operand) private byte RL(byte operand)
{ {
this.F = ClearBit(this.F, StatusBits.NF | StatusBits.HC); this.F = ClearBit(this.F, StatusBits.NF | StatusBits.HC);
var carry = this.F & (byte)StatusBits.CF; var carry = this.Carry();
this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit7); this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit7);
var result = (byte)((operand << 1) | carry); var result = (byte)((operand << 1) | carry);
this.F = AdjustXY(this.F, result); this.F = AdjustXY(this.F, result);
@ -1809,7 +1889,7 @@ namespace Z80
private byte RR(byte operand) private byte RR(byte operand)
{ {
this.F = ClearBit(this.F, StatusBits.NF | StatusBits.HC); this.F = ClearBit(this.F, StatusBits.NF | StatusBits.HC);
var carry = this.F & (byte)StatusBits.CF; var carry = this.Carry();
this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit0); this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit0);
var result = (byte)((operand >> 1) | (carry << 7)); var result = (byte)((operand >> 1) | (carry << 7));
this.F = AdjustXY(this.F, result); this.F = AdjustXY(this.F, result);
@ -1866,10 +1946,10 @@ namespace Z80
{ {
var updated = this.A; var updated = this.A;
var lowAdjust = (this.F & (byte)StatusBits.HC) != 0 || LowNibble(this.A) > 9; var lowAdjust = this.HalfCarry() != 0 || LowNibble(this.A) > 9;
var highAdjust = (this.F & (byte)StatusBits.CF) != 0 || this.A > 0x99; var highAdjust = this.Carry() != 0 || this.A > 0x99;
if ((this.F & (byte)StatusBits.NF) != 0) if (this.Subtracting() != 0)
{ {
if (lowAdjust) if (lowAdjust)
{ {
@ -1894,7 +1974,7 @@ namespace Z80
} }
} }
this.F = (byte)((this.F & (byte)(StatusBits.CF | StatusBits.NF)) | (this.A > 0x99 ? (byte)StatusBits.CF : 0) | ((this.A ^ updated) & (byte)StatusBits.HC)); this.F = (byte)((this.F & (byte)(StatusBits.CF | StatusBits.NF)) | (this.A > 0x99 ? (byte)StatusBits.CF : 0) | HalfCarryTest((byte)(this.A ^ updated)));
this.F = AdjustSZPXY(this.F, this.A = updated); this.F = AdjustSZPXY(this.F, this.A = updated);
} }
@ -1909,7 +1989,7 @@ namespace Z80
private void CCF() private void CCF()
{ {
this.F = ClearBit(this.F, StatusBits.NF); this.F = ClearBit(this.F, StatusBits.NF);
var carry = this.F & (byte)StatusBits.CF; var carry = this.Carry();
this.F = SetBit(this.F, StatusBits.HC, carry); this.F = SetBit(this.F, StatusBits.HC, carry);
this.F = ClearBit(this.F, StatusBits.CF, carry); this.F = ClearBit(this.F, StatusBits.CF, carry);
this.F = AdjustXY(this.F, this.A); this.F = AdjustXY(this.F, this.A);
@ -1945,7 +2025,7 @@ namespace Z80
this.F = AdjustHalfCarrySub(this.F, this.A, value, result); this.F = AdjustHalfCarrySub(this.F, this.A, value, result);
this.F = SetBit(this.F, StatusBits.NF); this.F = SetBit(this.F, StatusBits.NF);
result -= (byte)((this.F & (byte)StatusBits.HC) >> 4); result -= (byte)(this.HalfCarry() >> 4);
this.F = SetBit(this.F, StatusBits.YF, result & (byte)Bits.Bit1); this.F = SetBit(this.F, StatusBits.YF, result & (byte)Bits.Bit1);
this.F = SetBit(this.F, StatusBits.XF, result & (byte)Bits.Bit3); this.F = SetBit(this.F, StatusBits.XF, result & (byte)Bits.Bit3);
@ -1961,7 +2041,7 @@ namespace Z80
private bool CPIR() private bool CPIR()
{ {
this.CPI(); this.CPI();
return (this.F & (byte)StatusBits.PF) != 0 && (this.F & (byte)StatusBits.ZF) == 0; // See CPI return this.Parity() != 0 && this.Zero() == 0; // See CPI
} }
private void CPD() private void CPD()
@ -1974,7 +2054,7 @@ namespace Z80
private bool CPDR() private bool CPDR()
{ {
this.CPD(); this.CPD();
return (this.F & (byte)StatusBits.PF) != 0 && (this.F & (byte)StatusBits.ZF) == 0; // See CPD return this.Parity() != 0 && this.Zero() == 0; // See CPD
} }
private void BlockLoad(Register16 source, Register16 destination, ushort counter) private void BlockLoad(Register16 source, Register16 destination, ushort counter)
@ -1998,7 +2078,7 @@ namespace Z80
private bool LDIR() private bool LDIR()
{ {
this.LDI(); this.LDI();
return (this.F & (byte)StatusBits.PF) != 0; // See LDI return this.Parity() != 0; // See LDI
} }
private void LDD() private void LDD()
@ -2011,7 +2091,7 @@ namespace Z80
private bool LDDR() private bool LDDR()
{ {
this.LDD(); this.LDD();
return (this.F & (byte)StatusBits.PF) != 0; // See LDD return this.Parity() != 0; // See LDD
} }
private void BlockIn(Register16 source, Register16 destination) private void BlockIn(Register16 source, Register16 destination)
@ -2036,7 +2116,7 @@ namespace Z80
private bool INIR() private bool INIR()
{ {
this.INI(); this.INI();
return (this.F & (byte)StatusBits.ZF) == 0; // See INI return this.Zero() == 0; // See INI
} }
private void IND() private void IND()
@ -2049,7 +2129,7 @@ namespace Z80
private bool INDR() private bool INDR()
{ {
this.IND(); this.IND();
return (this.F & (byte)StatusBits.ZF) == 0; // See IND return this.Zero() == 0; // See IND
} }
private void BlockOut(Register16 source, Register16 destination) private void BlockOut(Register16 source, Register16 destination)
@ -2082,7 +2162,7 @@ namespace Z80
private bool OTIR() private bool OTIR()
{ {
this.OUTI(); this.OUTI();
return (this.F & (byte)StatusBits.ZF) == 0; // See OUTI return this.Zero() == 0; // See OUTI
} }
private void OUTD() private void OUTD()
@ -2096,7 +2176,7 @@ namespace Z80
private bool OTDR() private bool OTDR()
{ {
this.OUTD(); this.OUTD();
return (this.F & (byte)StatusBits.ZF) == 0; // See OUTD return this.Zero() == 0; // See OUTD
} }
private void NEG() private void NEG()