mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2026-03-11 05:41:49 +00:00
More sharing of concepts between all Intel style processors
This commit is contained in:
@@ -85,8 +85,9 @@ namespace Intel8080
|
||||
this.OnReadingMemory();
|
||||
this.Tick(2);
|
||||
base.MemoryRead();
|
||||
this.Tick();
|
||||
this.OnReadMemory();
|
||||
this.Tick(2);
|
||||
this.Tick();
|
||||
return this.Bus.Data;
|
||||
}
|
||||
|
||||
@@ -103,6 +104,14 @@ namespace Intel8080
|
||||
return this.Bus.Data;
|
||||
}
|
||||
|
||||
protected override void HandleINT()
|
||||
{
|
||||
base.HandleINT();
|
||||
var data = this.ReadDataUnderInterrupt();
|
||||
this.Tick();
|
||||
this.Execute(data);
|
||||
}
|
||||
|
||||
protected override void Call(Register16 destination)
|
||||
{
|
||||
this.Tick();
|
||||
@@ -115,14 +124,6 @@ namespace Intel8080
|
||||
this.Tick(5);
|
||||
}
|
||||
|
||||
protected override void HandleINT()
|
||||
{
|
||||
base.HandleINT();
|
||||
var data = this.ReadDataUnderInterrupt();
|
||||
this.Tick();
|
||||
this.Execute(data);
|
||||
}
|
||||
|
||||
private int Zero() => ZeroTest(this.F);
|
||||
|
||||
private int Carry() => CarryTest(this.F);
|
||||
@@ -145,14 +146,24 @@ namespace Intel8080
|
||||
|
||||
private static byte SetBit(byte f, StatusBits flag) => SetBit(f, (byte)flag);
|
||||
|
||||
private void SetBit(StatusBits flag) => this.F = SetBit(this.F, flag);
|
||||
|
||||
private static byte SetBit(byte f, StatusBits flag, int condition) => SetBit(f, (byte)flag, condition);
|
||||
|
||||
private void SetBit(StatusBits flag, int condition) => this.F = SetBit(this.F, flag, condition);
|
||||
|
||||
private static byte SetBit(byte f, StatusBits flag, bool condition) => SetBit(f, (byte)flag, condition);
|
||||
|
||||
private void SetBit(StatusBits flag, bool condition) => this.F = SetBit(this.F, flag, condition);
|
||||
|
||||
private static byte ClearBit(byte f, StatusBits flag) => ClearBit(f, (byte)flag);
|
||||
|
||||
private void ClearBit(StatusBits flag) => this.F = ClearBit(this.F, flag);
|
||||
|
||||
private static byte ClearBit(byte f, StatusBits flag, int condition) => ClearBit(f, (byte)flag, condition);
|
||||
|
||||
private void ClearBit(StatusBits flag, int condition) => this.F = ClearBit(this.F, flag, condition);
|
||||
|
||||
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);
|
||||
@@ -171,14 +182,38 @@ namespace Intel8080
|
||||
return AdjustParity(input, value);
|
||||
}
|
||||
|
||||
private void AdjustSZP(byte value) => this.F = AdjustSZP(this.F, value);
|
||||
|
||||
private static byte AdjustAuxiliaryCarryAdd(byte input, byte before, byte value, int calculation) => SetBit(input, StatusBits.AC, CalculateHalfCarryAdd(before, value, calculation));
|
||||
|
||||
private void AdjustAuxiliaryCarryAdd(byte before, byte value, int calculation) => this.F = AdjustAuxiliaryCarryAdd(this.F, before, value, calculation);
|
||||
|
||||
private static byte AdjustAuxiliaryCarrySub(byte input, byte before, byte value, int calculation) => ClearBit(input, StatusBits.AC, CalculateHalfCarrySub(before, value, calculation));
|
||||
|
||||
private void AdjustAuxiliaryCarrySub(byte before, byte value, int calculation) => this.F = AdjustAuxiliaryCarrySub(this.F, before, value, calculation);
|
||||
|
||||
protected override void DisableInterrupts() => this.interruptEnable = false;
|
||||
|
||||
protected override void EnableInterrupts() => this.interruptEnable = true;
|
||||
|
||||
private Register16 RP(int rp) => rp switch
|
||||
{
|
||||
0 => this.BC,
|
||||
1 => this.DE,
|
||||
2 => this.HL,
|
||||
3 => this.SP,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rp)),
|
||||
};
|
||||
|
||||
private Register16 RP2(int rp) => rp switch
|
||||
{
|
||||
0 => this.BC,
|
||||
1 => this.DE,
|
||||
2 => this.HL,
|
||||
3 => this.AF,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rp)),
|
||||
};
|
||||
|
||||
private ref byte R(int r, AccessLevel access = AccessLevel.ReadOnly)
|
||||
{
|
||||
switch (r)
|
||||
@@ -226,24 +261,6 @@ namespace Intel8080
|
||||
}
|
||||
}
|
||||
|
||||
private Register16 RP(int rp) => rp switch
|
||||
{
|
||||
0 => this.BC,
|
||||
1 => this.DE,
|
||||
2 => this.HL,
|
||||
3 => this.SP,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rp)),
|
||||
};
|
||||
|
||||
private Register16 RP2(int rp) => rp switch
|
||||
{
|
||||
0 => this.BC,
|
||||
1 => this.DE,
|
||||
2 => this.HL,
|
||||
3 => this.AF,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rp)),
|
||||
};
|
||||
|
||||
private void Execute(int x, int y, int z, int p, int q)
|
||||
{
|
||||
var memoryY = y == 6;
|
||||
@@ -403,37 +420,40 @@ namespace Intel8080
|
||||
this.R(y, this.R(z));
|
||||
}
|
||||
break;
|
||||
case 2: // Operate on accumulator and register/memory location
|
||||
switch (y)
|
||||
{
|
||||
case 0: // ADD A,r
|
||||
this.Add(this.R(z));
|
||||
break;
|
||||
case 1: // ADC A,r
|
||||
this.ADC(this.R(z));
|
||||
break;
|
||||
case 2: // SUB r
|
||||
this.SUB(this.R(z));
|
||||
break;
|
||||
case 3: // SBC A,r
|
||||
this.SBB(this.R(z));
|
||||
break;
|
||||
case 4: // AND r
|
||||
this.AndR(this.R(z));
|
||||
break;
|
||||
case 5: // XOR r
|
||||
this.XorR(this.R(z));
|
||||
break;
|
||||
case 6: // OR r
|
||||
this.OrR(this.R(z));
|
||||
break;
|
||||
case 7: // CP r
|
||||
this.Compare(this.R(z));
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Invalid operation mode");
|
||||
case 2:
|
||||
{ // Operate on accumulator and register/memory location
|
||||
var value = this.R(z);
|
||||
switch (y)
|
||||
{
|
||||
case 0: // ADD A,r
|
||||
this.A = this.Add(this.A, value);
|
||||
break;
|
||||
case 1: // ADC A,r
|
||||
this.A = this.ADC(this.A, value);
|
||||
break;
|
||||
case 2: // SUB r
|
||||
this.A = this.SUB(this.A, value);
|
||||
break;
|
||||
case 3: // SBC A,r
|
||||
this.A = this.SBC(this.A, value);
|
||||
break;
|
||||
case 4: // AND r
|
||||
this.AndR(value);
|
||||
break;
|
||||
case 5: // XOR r
|
||||
this.XorR(value);
|
||||
break;
|
||||
case 6: // OR r
|
||||
this.OrR(value);
|
||||
break;
|
||||
case 7: // CP r
|
||||
this.Compare(value);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Invalid operation mode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (z)
|
||||
{
|
||||
@@ -528,38 +548,40 @@ namespace Intel8080
|
||||
}
|
||||
|
||||
break;
|
||||
case 6: // Operate on accumulator and immediate operand: alu[y] n
|
||||
_ = this.FetchByte();
|
||||
switch (y)
|
||||
{
|
||||
case 0: // ADD A,n
|
||||
this.Add(this.Bus.Data);
|
||||
break;
|
||||
case 1: // ADC A,n
|
||||
this.ADC(this.Bus.Data);
|
||||
break;
|
||||
case 2: // SUB n
|
||||
this.SUB(this.Bus.Data);
|
||||
break;
|
||||
case 3: // SBC A,n
|
||||
this.SBB(this.Bus.Data);
|
||||
break;
|
||||
case 4: // AND n
|
||||
this.AndR(this.Bus.Data);
|
||||
break;
|
||||
case 5: // XOR n
|
||||
this.XorR(this.Bus.Data);
|
||||
break;
|
||||
case 6: // OR n
|
||||
this.OrR(this.Bus.Data);
|
||||
break;
|
||||
case 7: // CP n
|
||||
this.Compare(this.Bus.Data);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Invalid operation mode");
|
||||
case 6:
|
||||
{ // Operate on accumulator and immediate operand: alu[y] n
|
||||
var operand = this.FetchByte();
|
||||
switch (y)
|
||||
{
|
||||
case 0: // ADD A,n
|
||||
this.A = this.Add(this.A, operand);
|
||||
break;
|
||||
case 1: // ADC A,n
|
||||
this.A = this.ADC(this.A, operand);
|
||||
break;
|
||||
case 2: // SUB n
|
||||
this.A = this.SUB(this.A, operand);
|
||||
break;
|
||||
case 3: // SBC A,n
|
||||
this.A = this.SBC(this.A, operand);
|
||||
break;
|
||||
case 4: // AND n
|
||||
this.AndR(operand);
|
||||
break;
|
||||
case 5: // XOR n
|
||||
this.XorR(operand);
|
||||
break;
|
||||
case 6: // OR n
|
||||
this.OrR(operand);
|
||||
break;
|
||||
case 7: // CP n
|
||||
this.Compare(operand);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Invalid operation mode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 7: // Restart: RST y * 8
|
||||
this.Restart((byte)(y << 3));
|
||||
break;
|
||||
@@ -575,16 +597,18 @@ namespace Intel8080
|
||||
|
||||
private byte Increment(byte operand)
|
||||
{
|
||||
this.F = AdjustSZP(this.F, ++operand);
|
||||
this.F = ClearBit(this.F, StatusBits.AC, LowNibble(operand));
|
||||
return operand;
|
||||
var result = operand; ++operand;
|
||||
AdjustSZP(result);
|
||||
ClearBit(StatusBits.AC, LowNibble(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte Decrement(byte operand)
|
||||
{
|
||||
this.F = AdjustSZP(this.F, --operand);
|
||||
this.F = SetBit(this.F, StatusBits.AC, LowNibble(operand) != (byte)Mask.Four);
|
||||
return operand;
|
||||
var result = operand; --operand;
|
||||
AdjustSZP(result);
|
||||
SetBit(StatusBits.AC, LowNibble(result) != (byte)Mask.Four);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected sealed override bool ConvertCondition(int flag) => flag switch
|
||||
@@ -614,58 +638,58 @@ namespace Intel8080
|
||||
{
|
||||
var result = this.HL.Word + value.Word;
|
||||
this.HL.Word = (ushort)result;
|
||||
this.F = SetBit(this.F, StatusBits.CF, result & (int)Bits.Bit16);
|
||||
SetBit(StatusBits.CF, result & (int)Bits.Bit16);
|
||||
}
|
||||
|
||||
private void Add(byte value, int carry = 0)
|
||||
private byte Add(byte operand, byte value, int carry = 0)
|
||||
{
|
||||
this.MEMPTR.Word = (ushort)(this.A + value + carry);
|
||||
this.Intermediate.Word = (ushort)(operand + value + carry);
|
||||
var result = this.Intermediate.Low;
|
||||
|
||||
this.F = AdjustAuxiliaryCarryAdd(this.F, this.A, value, this.MEMPTR.Low);
|
||||
AdjustAuxiliaryCarryAdd(operand, value, result);
|
||||
|
||||
this.A = this.MEMPTR.Low;
|
||||
|
||||
this.F = SetBit(this.F, StatusBits.CF, CarryTest(this.MEMPTR.High));
|
||||
this.F = AdjustSZP(this.F, this.A);
|
||||
}
|
||||
|
||||
private void ADC(byte value) => this.Add(value, this.Carry());
|
||||
|
||||
private byte Subtract(byte operand, byte value, int carry = 0)
|
||||
{
|
||||
this.MEMPTR.Word = (ushort)(operand - value - carry);
|
||||
|
||||
this.F = AdjustAuxiliaryCarrySub(this.F, operand, value, this.MEMPTR.Word);
|
||||
|
||||
var result = this.MEMPTR.Low;
|
||||
|
||||
this.F = SetBit(this.F, StatusBits.CF, CarryTest(this.MEMPTR.High));
|
||||
this.F = AdjustSZP(this.F, result);
|
||||
SetBit(StatusBits.CF, CarryTest(this.Intermediate.High));
|
||||
AdjustSZP(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void SUB(byte value, int carry = 0) => this.A = this.Subtract(this.A, value, carry);
|
||||
private byte ADC(byte operand, byte value) => this.Add(operand, value, this.Carry());
|
||||
|
||||
private void SBB(byte value) => this.SUB(value, this.Carry());
|
||||
private byte Subtract(byte operand, byte value, int carry = 0)
|
||||
{
|
||||
this.Intermediate.Word = (ushort)(operand - value - carry);
|
||||
var result = this.Intermediate.Low;
|
||||
|
||||
AdjustAuxiliaryCarrySub(operand, value, this.Intermediate.Word);
|
||||
|
||||
SetBit(StatusBits.CF, CarryTest(this.Intermediate.High));
|
||||
AdjustSZP(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte SUB(byte operand, byte value, int carry = 0) => this.Subtract(operand, value, carry);
|
||||
|
||||
private byte SBC(byte operand, byte value) => this.SUB(operand, value, this.Carry());
|
||||
|
||||
private void AndR(byte value)
|
||||
{
|
||||
this.F = SetBit(this.F, StatusBits.AC, (this.A | value) & (int)Bits.Bit3);
|
||||
this.F = ClearBit(this.F, StatusBits.CF);
|
||||
this.F = AdjustSZP(this.F, this.A &= value);
|
||||
SetBit(StatusBits.AC, (this.A | value) & (int)Bits.Bit3);
|
||||
ClearBit(StatusBits.CF);
|
||||
AdjustSZP(this.A &= value);
|
||||
}
|
||||
|
||||
private void XorR(byte value)
|
||||
{
|
||||
this.F = ClearBit(this.F, StatusBits.AC | StatusBits.CF);
|
||||
this.F = AdjustSZP(this.F, this.A ^= value);
|
||||
ClearBit(StatusBits.AC | StatusBits.CF);
|
||||
AdjustSZP(this.A ^= value);
|
||||
}
|
||||
|
||||
private void OrR(byte value)
|
||||
{
|
||||
this.F = ClearBit(this.F, StatusBits.AC | StatusBits.CF);
|
||||
this.F = AdjustSZP(this.F, this.A |= value);
|
||||
ClearBit(StatusBits.AC | StatusBits.CF);
|
||||
AdjustSZP(this.A |= value);
|
||||
}
|
||||
|
||||
private void Compare(byte value) => this.Subtract(this.A, value);
|
||||
@@ -673,28 +697,28 @@ namespace Intel8080
|
||||
private byte RLC(byte operand)
|
||||
{
|
||||
var carry = operand & (byte)Bits.Bit7;
|
||||
this.F = SetBit(this.F, StatusBits.CF, carry);
|
||||
SetBit(StatusBits.CF, carry);
|
||||
return (byte)((operand << 1) | (carry >> 7));
|
||||
}
|
||||
|
||||
private byte RRC(byte operand)
|
||||
{
|
||||
var carry = operand & (byte)Bits.Bit0;
|
||||
this.F = SetBit(this.F, StatusBits.CF, carry);
|
||||
SetBit(StatusBits.CF, carry);
|
||||
return (byte)((operand >> 1) | (carry << 7));
|
||||
}
|
||||
|
||||
private byte RL(byte operand)
|
||||
{
|
||||
var carry = this.Carry();
|
||||
this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit7);
|
||||
SetBit(StatusBits.CF, operand & (byte)Bits.Bit7);
|
||||
return (byte)((operand << 1) | carry);
|
||||
}
|
||||
|
||||
private byte RR(byte operand)
|
||||
{
|
||||
var carry = this.Carry();
|
||||
this.F = SetBit(this.F, StatusBits.CF, operand & (byte)Bits.Bit0);
|
||||
SetBit(StatusBits.CF, operand & (byte)Bits.Bit0);
|
||||
return (byte)((operand >> 1) | (carry << 7));
|
||||
}
|
||||
|
||||
@@ -714,15 +738,15 @@ namespace Intel8080
|
||||
carry = true;
|
||||
}
|
||||
|
||||
this.Add(addition);
|
||||
this.F = SetBit(this.F, StatusBits.CF, carry);
|
||||
this.A = this.Add(this.A, addition);
|
||||
SetBit(StatusBits.CF, carry);
|
||||
}
|
||||
|
||||
private void CMA() => this.A = (byte)~this.A;
|
||||
|
||||
private void STC() => this.F = SetBit(this.F, StatusBits.CF);
|
||||
private void STC() => SetBit(StatusBits.CF);
|
||||
|
||||
private void CMC() => this.F = ClearBit(this.F, StatusBits.CF, this.Carry());
|
||||
private void CMC() => ClearBit(StatusBits.CF, this.Carry());
|
||||
|
||||
private void XHTL(Register16 exchange)
|
||||
{
|
||||
|
||||
@@ -324,9 +324,9 @@ namespace LR35902
|
||||
|
||||
private static byte AdjustHalfCarrySub(byte input, byte before, byte value, int calculation) => SetBit(input, StatusBits.HC, CalculateHalfCarrySub(before, value, 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));
|
||||
|
||||
private static byte Set(int n, byte operand) => SetBit(operand, Bit(n));
|
||||
private static byte SET(int n, byte operand) => SetBit(operand, Bit(n));
|
||||
|
||||
protected override void DisableInterrupts() => this.IME = false;
|
||||
|
||||
@@ -336,23 +336,28 @@ namespace LR35902
|
||||
|
||||
private void Start() => this.Stopped = false;
|
||||
|
||||
protected override void MemoryWrite()
|
||||
private void MemoryUpdate(int ticks)
|
||||
{
|
||||
this.LowerMWR();
|
||||
this.LowerWR();
|
||||
base.MemoryWrite();
|
||||
this.TickMachine();
|
||||
this.RaiseWR();
|
||||
this.LowerWR();
|
||||
base.MemoryWrite();
|
||||
this.TickMachine(ticks);
|
||||
this.RaiseWR();
|
||||
this.RaiseMWR();
|
||||
}
|
||||
|
||||
protected override void MemoryWrite()
|
||||
{
|
||||
this.MemoryUpdate(1);
|
||||
}
|
||||
|
||||
protected override byte MemoryRead()
|
||||
{
|
||||
this.LowerMWR();
|
||||
this.LowerRD();
|
||||
_ = base.MemoryRead();
|
||||
this.TickMachine();
|
||||
this.RaiseRD();
|
||||
this.LowerRD();
|
||||
_ = base.MemoryRead();
|
||||
this.TickMachine();
|
||||
this.RaiseRD();
|
||||
this.RaiseMWR();
|
||||
return this.Bus.Data;
|
||||
}
|
||||
@@ -396,52 +401,53 @@ namespace LR35902
|
||||
this.TickMachine();
|
||||
}
|
||||
|
||||
private byte R(int r) => r switch
|
||||
{
|
||||
0 => this.B,
|
||||
1 => this.C,
|
||||
2 => this.D,
|
||||
3 => this.E,
|
||||
4 => this.H,
|
||||
5 => this.L,
|
||||
6 => this.MemoryRead(this.HL),
|
||||
7 => this.A,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(r)),
|
||||
};
|
||||
|
||||
private void R(int r, byte value)
|
||||
private ref byte R(int r, AccessLevel access = AccessLevel.ReadOnly)
|
||||
{
|
||||
switch (r)
|
||||
{
|
||||
case 0:
|
||||
this.B = value;
|
||||
break;
|
||||
return ref this.B;
|
||||
case 1:
|
||||
this.C = value;
|
||||
break;
|
||||
return ref this.C;
|
||||
case 2:
|
||||
this.D = value;
|
||||
break;
|
||||
return ref this.D;
|
||||
case 3:
|
||||
this.E = value;
|
||||
break;
|
||||
return ref this.E;
|
||||
case 4:
|
||||
this.H = value;
|
||||
break;
|
||||
return ref this.H;
|
||||
case 5:
|
||||
this.L = value;
|
||||
break;
|
||||
return ref this.L;
|
||||
case 6:
|
||||
this.MemoryWrite(this.HL, value);
|
||||
break;
|
||||
this.Bus.Address.Assign(this.HL);
|
||||
switch (access)
|
||||
{
|
||||
case AccessLevel.ReadOnly:
|
||||
this.MemoryRead();
|
||||
break;
|
||||
case AccessLevel.WriteOnly:
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Invalid access level");
|
||||
}
|
||||
|
||||
// Will need a post-MemoryWrite
|
||||
return ref this.Bus.Data;
|
||||
case 7:
|
||||
this.A = value;
|
||||
break;
|
||||
return ref this.A;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(r));
|
||||
}
|
||||
}
|
||||
|
||||
private void R(int r, byte value, int ticks = 1)
|
||||
{
|
||||
this.R(r, AccessLevel.WriteOnly) = value;
|
||||
if (r == 6)
|
||||
{
|
||||
this.MemoryUpdate(ticks);
|
||||
}
|
||||
}
|
||||
|
||||
private Register16 RP(int rp) => rp switch
|
||||
{
|
||||
0 => this.BC,
|
||||
@@ -462,11 +468,12 @@ namespace LR35902
|
||||
|
||||
private void ExecuteCB(int x, int y, int z)
|
||||
{
|
||||
var operand = this.R(z);
|
||||
var update = x != 1; // BIT does not update
|
||||
switch (x)
|
||||
{
|
||||
case 0: // rot[y] r[z]
|
||||
{
|
||||
var operand = this.R(z);
|
||||
operand = y switch
|
||||
{
|
||||
0 => this.RLC(operand),
|
||||
@@ -479,30 +486,36 @@ namespace LR35902
|
||||
7 => this.SRL(operand),
|
||||
_ => throw new InvalidOperationException("Unreachable code block reached"),
|
||||
};
|
||||
this.R(z, operand);
|
||||
this.AdjustZero(operand);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // BIT y, r[z]
|
||||
this.Bit(y, this.R(z));
|
||||
this.Bit(y, operand);
|
||||
break;
|
||||
|
||||
case 2: // RES y, r[z]
|
||||
this.R(z, Res(y, this.R(z)));
|
||||
operand = RES(y, operand);
|
||||
break;
|
||||
|
||||
case 3: // SET y, r[z]
|
||||
this.R(z, Set(y, this.R(z)));
|
||||
operand = SET(y, operand);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Unreachable code block reached");
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
this.R(z, operand);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteOther(int x, int y, int z, int p, int q)
|
||||
{
|
||||
var memoryY = y == 6;
|
||||
var memoryZ = z == 6;
|
||||
switch (x)
|
||||
{
|
||||
case 0:
|
||||
@@ -544,7 +557,8 @@ namespace LR35902
|
||||
break;
|
||||
|
||||
case 1: // ADD HL,rp
|
||||
this.Add(this.HL, this.RP(p));
|
||||
this.Add(this.RP(p));
|
||||
this.TickMachine();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -616,14 +630,18 @@ namespace LR35902
|
||||
break;
|
||||
|
||||
case 3: // 16-bit INC/DEC
|
||||
_ = q switch
|
||||
switch (q)
|
||||
{
|
||||
// INC rp
|
||||
0 => this.RP(p).Increment(),
|
||||
// DEC rp
|
||||
1 => this.RP(p).Decrement(),
|
||||
_ => throw new InvalidOperationException("Invalid operation mode"),
|
||||
};
|
||||
case 0: // INC rp
|
||||
this.RP(p).Increment();
|
||||
break;
|
||||
|
||||
case 1: // DEC rp
|
||||
this.RP(p).Decrement();
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid operation mode");
|
||||
}
|
||||
this.TickMachine();
|
||||
break;
|
||||
|
||||
@@ -678,48 +696,51 @@ namespace LR35902
|
||||
break;
|
||||
|
||||
case 1: // 8-bit loading
|
||||
if (z == 6 && y == 6)
|
||||
if (!(memoryZ && memoryY))
|
||||
{
|
||||
this.R(y, this.R(z));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LowerHALT(); // Exception (replaces LD (HL), (HL))
|
||||
this.TickMachine(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.R(y, this.R(z));
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // Operate on accumulator and register/memory location
|
||||
switch (y)
|
||||
{
|
||||
case 0: // ADD A,r
|
||||
this.A = this.Add(this.A, this.R(z));
|
||||
break;
|
||||
case 1: // ADC A,r
|
||||
this.A = this.ADC(this.A, this.R(z));
|
||||
break;
|
||||
case 2: // SUB r
|
||||
this.A = this.Subtract(this.A, this.R(z));
|
||||
break;
|
||||
case 3: // SBC A,r
|
||||
this.A = this.SBC(this.A, this.R(z));
|
||||
break;
|
||||
case 4: // AND r
|
||||
this.AndR(this.R(z));
|
||||
break;
|
||||
case 5: // XOR r
|
||||
this.XorR(this.R(z));
|
||||
break;
|
||||
case 6: // OR r
|
||||
this.OrR(this.R(z));
|
||||
break;
|
||||
case 7: // CP r
|
||||
this.Compare(this.R(z));
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid operation mode");
|
||||
case 2:
|
||||
{ // Operate on accumulator and register/memory location
|
||||
var value = this.R(z);
|
||||
switch (y)
|
||||
{
|
||||
case 0: // ADD A,r
|
||||
this.A = this.Add(this.A, value);
|
||||
break;
|
||||
case 1: // ADC A,r
|
||||
this.A = this.ADC(this.A, value);
|
||||
break;
|
||||
case 2: // SUB r
|
||||
this.A = this.Subtract(this.A, value);
|
||||
break;
|
||||
case 3: // SBC A,r
|
||||
this.A = this.SBC(this.A, value);
|
||||
break;
|
||||
case 4: // AND r
|
||||
this.AndR(value);
|
||||
break;
|
||||
case 5: // XOR r
|
||||
this.XorR(value);
|
||||
break;
|
||||
case 6: // OR r
|
||||
this.OrR(value);
|
||||
break;
|
||||
case 7: // CP r
|
||||
this.Compare(value);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid operation mode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (z)
|
||||
{
|
||||
@@ -886,38 +907,40 @@ namespace LR35902
|
||||
|
||||
break;
|
||||
|
||||
case 6: // Operate on accumulator and immediate operand: alu[y] n
|
||||
_ = this.FetchByte();
|
||||
switch (y)
|
||||
{
|
||||
case 0: // ADD A,n
|
||||
this.A = this.Add(this.A, this.Bus.Data);
|
||||
break;
|
||||
case 1: // ADC A,n
|
||||
this.A = this.ADC(this.A, this.Bus.Data);
|
||||
break;
|
||||
case 2: // SUB n
|
||||
this.A = this.Subtract(this.A, this.Bus.Data);
|
||||
break;
|
||||
case 3: // SBC A,n
|
||||
this.A = this.SBC(this.A, this.Bus.Data);
|
||||
break;
|
||||
case 4: // AND n
|
||||
this.AndR(this.Bus.Data);
|
||||
break;
|
||||
case 5: // XOR n
|
||||
this.XorR(this.Bus.Data);
|
||||
break;
|
||||
case 6: // OR n
|
||||
this.OrR(this.Bus.Data);
|
||||
break;
|
||||
case 7: // CP n
|
||||
this.Compare(this.Bus.Data);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid operation mode");
|
||||
case 6:
|
||||
{ // Operate on accumulator and immediate operand: alu[y] n
|
||||
var operand = this.FetchByte();
|
||||
switch (y)
|
||||
{
|
||||
case 0: // ADD A,n
|
||||
this.A = this.Add(this.A, operand);
|
||||
break;
|
||||
case 1: // ADC A,n
|
||||
this.A = this.ADC(this.A, operand);
|
||||
break;
|
||||
case 2: // SUB n
|
||||
this.A = this.Subtract(this.A, operand);
|
||||
break;
|
||||
case 3: // SBC A,n
|
||||
this.A = this.SBC(this.A, operand);
|
||||
break;
|
||||
case 4: // AND n
|
||||
this.AndR(operand);
|
||||
break;
|
||||
case 5: // XOR n
|
||||
this.XorR(operand);
|
||||
break;
|
||||
case 6: // OR n
|
||||
this.OrR(operand);
|
||||
break;
|
||||
case 7: // CP n
|
||||
this.Compare(operand);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid operation mode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: // Restart: RST y * 8
|
||||
this.Restart((byte)(y << 3));
|
||||
@@ -936,17 +959,19 @@ namespace LR35902
|
||||
private byte Increment(byte operand)
|
||||
{
|
||||
this.ClearBit(StatusBits.NF);
|
||||
this.AdjustZero(++operand);
|
||||
this.ClearBit(StatusBits.HC, LowNibble(operand));
|
||||
return operand;
|
||||
var result = operand; ++result;
|
||||
this.AdjustZero(result);
|
||||
this.ClearBit(StatusBits.HC, LowNibble(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte Decrement(byte operand)
|
||||
{
|
||||
this.SetBit(StatusBits.NF);
|
||||
this.ClearBit(StatusBits.HC, LowNibble(operand));
|
||||
this.AdjustZero(--operand);
|
||||
return operand;
|
||||
var result = operand; --result;
|
||||
this.AdjustZero(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected sealed override bool ConvertCondition(int flag) => flag switch
|
||||
@@ -958,49 +983,42 @@ namespace LR35902
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(flag)),
|
||||
};
|
||||
|
||||
private void Add(Register16 operand, Register16 value)
|
||||
private void Add(Register16 value)
|
||||
{
|
||||
this.TickMachine();
|
||||
|
||||
this.MEMPTR.Assign(operand);
|
||||
|
||||
var result = this.MEMPTR.Word + value.Word;
|
||||
|
||||
operand.Word = (ushort)result;
|
||||
|
||||
this.Intermediate.Assign(this.HL);
|
||||
var result = this.HL.Word + value.Word;
|
||||
this.HL.Word = (ushort)result;
|
||||
this.ClearBit(StatusBits.NF);
|
||||
this.SetBit(StatusBits.CF, result & (int)Bits.Bit16);
|
||||
this.AdjustHalfCarryAdd(this.MEMPTR.High, value.High, operand.High);
|
||||
this.AdjustHalfCarryAdd(this.Intermediate.High, value.High, this.HL.High);
|
||||
}
|
||||
|
||||
private byte Add(byte operand, byte value, int carry = 0)
|
||||
{
|
||||
this.MEMPTR.Word = (ushort)(operand + value + carry);
|
||||
this.Intermediate.Word = (ushort)(operand + value + carry);
|
||||
var result = this.Intermediate.Low;
|
||||
|
||||
this.AdjustHalfCarryAdd(operand, value, this.MEMPTR.Low);
|
||||
|
||||
operand = this.MEMPTR.Low;
|
||||
this.AdjustHalfCarryAdd(operand, value, result);
|
||||
|
||||
this.ClearBit(StatusBits.NF);
|
||||
this.SetBit(StatusBits.CF, this.MEMPTR.Word & (ushort)Bits.Bit8);
|
||||
this.AdjustZero(operand);
|
||||
this.SetBit(StatusBits.CF, this.Intermediate.High & (byte)Bits.Bit0);
|
||||
this.AdjustZero(result);
|
||||
|
||||
return operand;
|
||||
return result;
|
||||
}
|
||||
|
||||
private byte ADC(byte operand, byte value) => this.Add(operand, value, this.Carry() >> 4);
|
||||
|
||||
private byte Subtract(byte operand, byte value, int carry = 0)
|
||||
{
|
||||
this.MEMPTR.Word = (ushort)(operand - value - carry);
|
||||
this.Intermediate.Word = (ushort)(operand - value - carry);
|
||||
var result = this.Intermediate.Low;
|
||||
|
||||
this.AdjustHalfCarrySub(operand, value, this.MEMPTR.Low);
|
||||
|
||||
var result = operand = this.MEMPTR.Low;
|
||||
this.AdjustHalfCarrySub(operand, value, result);
|
||||
|
||||
this.SetBit(StatusBits.NF);
|
||||
this.SetBit(StatusBits.CF, this.MEMPTR.High & (byte)Bits.Bit0);
|
||||
this.AdjustZero(operand);
|
||||
this.SetBit(StatusBits.CF, this.Intermediate.High & (byte)Bits.Bit0);
|
||||
this.AdjustZero(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
44
Z80/Z80.cs
44
Z80/Z80.cs
@@ -933,7 +933,7 @@ namespace Z80
|
||||
switch (z)
|
||||
{
|
||||
case 0: // Input from port with 16-bit address
|
||||
_ = this.ReadPort(this.BC);
|
||||
this.ReadPort(this.BC);
|
||||
this.MEMPTR.Increment();
|
||||
if (y != 6)
|
||||
{
|
||||
@@ -1480,7 +1480,8 @@ namespace Z80
|
||||
this.WritePort(this.FetchByte());
|
||||
break;
|
||||
case 3: // IN A,(n)
|
||||
this.A = this.ReadPort(this.FetchByte());
|
||||
this.ReadPort(this.FetchByte());
|
||||
this.A = this.Bus.Data;
|
||||
break;
|
||||
case 4: // EX (SP),HL
|
||||
this.XHTL(this.HL2());
|
||||
@@ -2138,7 +2139,7 @@ namespace Z80
|
||||
private void BlockIn()
|
||||
{
|
||||
this.Tick();
|
||||
_ = this.ReadPort(this.BC);
|
||||
this.ReadPort(this.BC);
|
||||
this.Bus.Address.Assign(this.HL);
|
||||
this.MemoryUpdate(1);
|
||||
this.AdjustSZXY(--this.B);
|
||||
@@ -2293,6 +2294,12 @@ namespace Z80
|
||||
|
||||
#region Input/output port control
|
||||
|
||||
private void WritePort(Register16 port, byte data)
|
||||
{
|
||||
this.Bus.Data = data;
|
||||
this.WritePort(port);
|
||||
}
|
||||
|
||||
private void WritePort(byte port)
|
||||
{
|
||||
this.Bus.Address.Assign(port, this.Bus.Data = this.A);
|
||||
@@ -2300,12 +2307,6 @@ namespace Z80
|
||||
++this.MEMPTR.Low;
|
||||
}
|
||||
|
||||
private void WritePort(Register16 port, byte data)
|
||||
{
|
||||
this.Bus.Data = data;
|
||||
this.WritePort(port);
|
||||
}
|
||||
|
||||
private void WritePort(Register16 port)
|
||||
{
|
||||
this.Bus.Address.Assign(port);
|
||||
@@ -2315,8 +2316,7 @@ namespace Z80
|
||||
private void WritePort()
|
||||
{
|
||||
this.MEMPTR.Assign(this.Bus.Address);
|
||||
this.Tick();
|
||||
this.Tick();
|
||||
this.Tick(2);
|
||||
this.LowerIORQ();
|
||||
this.LowerWR();
|
||||
this.Tick();
|
||||
@@ -2326,21 +2326,20 @@ namespace Z80
|
||||
this.Tick();
|
||||
}
|
||||
|
||||
private byte ReadPort(byte port)
|
||||
{
|
||||
this.Bus.Address.Assign(port, this.Bus.Data = this.A);
|
||||
_ = this.ReadPort();
|
||||
this.MEMPTR.Increment();
|
||||
return this.Bus.Data;
|
||||
}
|
||||
|
||||
private byte ReadPort(Register16 port)
|
||||
private void ReadPort(Register16 port)
|
||||
{
|
||||
this.Bus.Address.Assign(port);
|
||||
return this.ReadPort();
|
||||
this.ReadPort();
|
||||
}
|
||||
|
||||
private byte ReadPort()
|
||||
private void ReadPort(byte port)
|
||||
{
|
||||
this.Bus.Address.Assign(port, this.Bus.Data = this.A);
|
||||
this.ReadPort();
|
||||
this.MEMPTR.Increment();
|
||||
}
|
||||
|
||||
private void ReadPort()
|
||||
{
|
||||
this.MEMPTR.Assign(this.Bus.Address);
|
||||
this.Tick(2);
|
||||
@@ -2351,7 +2350,6 @@ namespace Z80
|
||||
this.RaiseRD();
|
||||
this.RaiseIORQ();
|
||||
this.Tick();
|
||||
return this.Bus.Data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user