diff --git a/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/Execute.cs b/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/Execute.cs
index d2aff337beb..381c0ded218 100644
--- a/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/Execute.cs
+++ b/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/Execute.cs
@@ -179,7 +179,7 @@ static MOS6502X()
/*DEY [implied]*/ new Uop[] { Uop.Imp_DEY, Uop.End },
/*NOP #nn [immediate]*/ new Uop[] { Uop.Imm_Unsupported, Uop.End },
/*TXA [implied]*/ new Uop[] { Uop.Imp_TXA, Uop.End },
- /*ANE** [immediate] [unofficial]*/ new Uop[] { Uop.Imm_Unsupported, Uop.End },
+ /*ANE** [immediate] [unofficial]*/ new Uop[] { Uop.Imm_ANE, Uop.End },
/*STY addr [absolute WRITE]*/ new Uop[] { Uop.Fetch2, Uop.Fetch3, Uop.Abs_WRITE_STY, Uop.End },
/*STA addr [absolute WRITE]*/ new Uop[] { Uop.Fetch2, Uop.Fetch3, Uop.Abs_WRITE_STA, Uop.End },
/*STX addr [absolute WRITE]*/ new Uop[] { Uop.Fetch2, Uop.Fetch3, Uop.Abs_WRITE_STX, Uop.End },
@@ -188,7 +188,7 @@ static MOS6502X()
/*BCC +/-rel [relative]*/ new Uop[] { Uop.RelBranch_Stage2_BCC, Uop.End },
/*STA (addr),Y [indirect indexed WRITE]*/ new Uop[] { Uop.Fetch2, Uop.IndIdx_Stage3, Uop.IndIdx_Stage4, Uop.IndIdx_WRITE_Stage5, Uop.IndIdx_WRITE_Stage6_STA, Uop.End },
/*JAM*/ new Uop[] { Uop.Jam },
- /*SHA** [indirect indexed WRITE] [unofficial] [not tested by blargg's instruction tests]*/ new Uop[] { Uop.Fetch2, Uop.IndIdx_Stage3, Uop.IndIdx_Stage4, Uop.IndIdx_WRITE_Stage5, Uop.IndIdx_WRITE_Stage6_SHA, Uop.End },
+ /*SHA** [indirect indexed WRITE] [unofficial] [not tested by blargg's instruction tests]*/ new Uop[] { Uop.Fetch2, Uop.IndIdx_Stage3, Uop.IndIdx_Stage4, Uop.IndIdx_WRITE_Stage5_SHA, Uop.IndIdx_WRITE_Stage6_SHA, Uop.End },
/*STY zp,X [zero page indexed WRITE X]*/ new Uop[] { Uop.Fetch2, Uop.ZpIdx_Stage3_X, Uop.ZP_WRITE_STY, Uop.End },
/*STA zp,X [zero page indexed WRITE X]*/ new Uop[] { Uop.Fetch2, Uop.ZpIdx_Stage3_X, Uop.ZP_WRITE_STA, Uop.End },
/*STX zp,Y [zero page indexed WRITE Y]*/ new Uop[] { Uop.Fetch2, Uop.ZpIdx_Stage3_Y, Uop.ZP_WRITE_STX, Uop.End },
@@ -197,10 +197,10 @@ static MOS6502X()
/*STA addr,Y [absolute indexed WRITE]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_Y, Uop.AbsIdx_Stage4, Uop.AbsIdx_WRITE_Stage5_STA, Uop.End },
/*TXS [implied]*/ new Uop[] { Uop.Imp_TXS, Uop.End },
/*SHS* addr,Y [absolute indexed WRITE Y] [unofficial] */ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_Y, Uop.AbsIdx_Stage4, Uop.AbsIdx_WRITE_Stage5_ERROR, Uop.End },
- /*SHY** [absolute indexed WRITE] [unofficial]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_X, Uop.AbsIdx_Stage4, Uop.AbsIdx_WRITE_Stage5_SHY, Uop.End },
+ /*SHY** [absolute indexed WRITE] [unofficial]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_X, Uop.AbsIdx_Stage4_SHY, Uop.AbsIdx_WRITE_Stage5_SHY, Uop.End },
/*STA addr,X [absolute indexed WRITE]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_X, Uop.AbsIdx_Stage4, Uop.AbsIdx_WRITE_Stage5_STA, Uop.End },
- /*SHX* addr,Y [absolute indexed WRITE Y] [unofficial]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_Y, Uop.AbsIdx_Stage4, Uop.AbsIdx_WRITE_Stage5_SHX, Uop.End },
- /*SHA* addr,Y [absolute indexed WRITE Y] [unofficial]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_Y, Uop.AbsIdx_Stage4, Uop.AbsIdx_WRITE_Stage5_SHY, Uop.End },
+ /*SHX* addr,Y [absolute indexed WRITE Y] [unofficial]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_Y, Uop.AbsIdx_Stage4_SHX, Uop.AbsIdx_WRITE_Stage5_SHX, Uop.End },
+ /*SHA* addr,Y [absolute indexed WRITE Y] [unofficial]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_Y, Uop.AbsIdx_Stage4_SHA, Uop.AbsIdx_WRITE_Stage5_SHA, Uop.End },
//0xA0
/*LDY #nn [immediate]*/ new Uop[] { Uop.Imm_LDY, Uop.End },
/*LDA (addr,X) [indexed indirect READ]*/ new Uop[] { Uop.Fetch2, Uop.IdxInd_Stage3, Uop.IdxInd_Stage4, Uop.IdxInd_Stage5, Uop.IdxInd_Stage6_READ_LDA, Uop.End },
@@ -466,7 +466,15 @@ private enum Uop
End_ISpecial, //same as end, but preserves the iflag set by the instruction
End_SuppressInterrupt,
- Jam
+ Jam,
+
+ // More unofficial micro-ops
+ Imm_ANE,
+ AbsIdx_WRITE_Stage5_SHA,
+ IndIdx_WRITE_Stage5_SHA,
+ AbsIdx_Stage4_SHX,
+ AbsIdx_Stage4_SHY,
+ AbsIdx_Stage4_SHA
}
private void InitOpcodeHandlers()
@@ -946,6 +954,22 @@ private void IndIdx_WRITE_Stage5()
}
}
+ private void IndIdx_WRITE_Stage5_SHA()
+ {
+ rdy_freeze = !RDY;
+ if (RDY)
+ {
+ _link.ReadMemory((ushort) ea);
+
+ if (alu_temp.Bit(8))
+ {
+ ea = (ushort) (ea & 0xFF | ((ea + 0x100) & 0xFF00 & ((A & X) << 8)));
+ }
+
+ ea += unchecked((ushort) (alu_temp & 0xFF00));
+ }
+ }
+
private void IndIdx_READ_Stage5()
{
if (!alu_temp.Bit(8))
@@ -984,7 +1008,14 @@ private void IndIdx_WRITE_Stage6_STA()
private void IndIdx_WRITE_Stage6_SHA()
{
- _link.WriteMemory((ushort)ea, (byte)(A & X & 7));
+ alu_temp = A & X;
+
+ if (RDY)
+ {
+ alu_temp &= unchecked((byte) ((ea >> 8) + 1));
+ }
+
+ _link.WriteMemory((ushort) ea, unchecked((byte) alu_temp));
}
private void IndIdx_READ_Stage6_LDA()
@@ -1697,8 +1728,35 @@ private void _Axs()
private void _Arr()
{
+ A &= unchecked((byte) alu_temp);
+
+ if (FlagD && BCD_Enabled)
+ {
+ // Shift logic
+ var next = (A >> 1) | (FlagC ? 0x80 : 0x00);
+ FlagV = ((A ^ next) & 0x40) != 0;
+ FlagN = FlagC;
+ FlagZ = (next & 0xFF) == 0;
+
+ // BCD fixup
+ if ((A & 0x0F) + (A & 0x01) > 0x05)
+ {
+ next = (next & 0xF0) | ((next + 0x06) & 0x0F);
+ }
+ if ((A & 0xF0) + (A & 0x10) > 0x50)
+ {
+ next = (next & 0x0F) | ((next + 0x60) & 0xF0);
+ FlagC = true;
+ }
+ else
+ {
+ FlagC = false;
+ }
+
+ A = unchecked((byte) next);
+ }
+ else
{
- A &= (byte)alu_temp;
booltemp = A.Bit(0);
A = (byte)((A >> 1) | (FlagC ? 0x80 : 0x00));
FlagC = booltemp;
@@ -1709,13 +1767,24 @@ private void _Arr()
else if (A.Bit(6))
{ FlagV = true; FlagC = true; }
else { FlagV = false; FlagC = false; }
- FlagZ = (A == 0);
+ NZ_A();
}
}
+ private void _Ane()
+ {
+ // Many varied reports on what this should be.
+ // A safe value is 0xFF. Commodore 64 needs 0xEF.
+ A |= AneConstant;
+ A &= unchecked((byte) (X & alu_temp));
+ NZ_A();
+ }
+
private void _Lxa()
{
- A |= 0xFF; //there is some debate about what this should be. it may depend on the 6502 variant. this is suggested by qeed's doc for the nes and passes blargg's instruction test
+ //there is some debate about what this should be. it may depend on the 6502 variant.
+ //this is suggested by qeed's doc for the nes and passes blargg's instruction test
+ A |= LxaConstant;
A &= (byte)alu_temp;
X = A;
NZ_A();
@@ -1723,26 +1792,26 @@ private void _Lxa()
private void _Sbc()
{
+ value8 = unchecked((byte) alu_temp);
+ tempint = A - value8 - (FlagC ? 0 : 1);
+ if (FlagD && BCD_Enabled)
{
- value8 = (byte)alu_temp;
- tempint = A - value8 - (FlagC ? 0 : 1);
- if (FlagD && BCD_Enabled)
- {
- lo = (A & 0x0F) - (value8 & 0x0F) - (FlagC ? 0 : 1);
- hi = (A & 0xF0) - (value8 & 0xF0);
- if ((lo & 0xF0) != 0) lo -= 0x06;
- if ((lo & 0x80) != 0) hi -= 0x10;
- if ((hi & 0x0F00) != 0) hi -= 0x60;
- FlagV = ((A ^ value8) & (A ^ tempint) & 0x80) != 0;
- FlagC = (hi & 0xFF00) == 0;
- A = (byte)((lo & 0x0F) | (hi & 0xF0));
- }
- else
- {
- FlagV = ((A ^ value8) & (A ^ tempint) & 0x80) != 0;
- FlagC = tempint >= 0;
- A = (byte)tempint;
- }
+ lo = (A & 0x0F) - (value8 & 0x0F) - (FlagC ? 0 : 1);
+ hi = (A & 0xF0) - (value8 & 0xF0);
+ if ((lo & 0xF0) != 0) lo -= 0x06;
+ if ((lo & 0x80) != 0) hi -= 0x10;
+ if ((hi & 0x0F00) != 0) hi -= 0x60;
+ FlagV = ((A ^ value8) & (A ^ tempint) & 0x80) != 0;
+ FlagZ = (tempint & 0xFF) == 0;
+ FlagN = (tempint & 0x80) != 0;
+ FlagC = (hi & 0xFF00) == 0;
+ A = unchecked((byte) ((lo & 0x0F) | (hi & 0xF0)));
+ }
+ else
+ {
+ FlagV = ((A ^ value8) & (A ^ tempint) & 0x80) != 0;
+ FlagC = tempint >= 0;
+ A = unchecked((byte) tempint);
NZ_A();
}
}
@@ -1941,6 +2010,16 @@ private void Imm_LDY()
}
}
+ private void Imm_ANE()
+ {
+ rdy_freeze = !RDY;
+ if (RDY)
+ {
+ alu_temp = _link.ReadMemory(PC++);
+ _Ane();
+ }
+ }
+
private void Imm_Unsupported()
{
rdy_freeze = !RDY;
@@ -2411,16 +2490,64 @@ private void AbsIdx_READ_Stage4()
private void AbsIdx_Stage4()
{
rdy_freeze = !RDY;
+
if (RDY)
{
- //bleh.. redundant code to make sure we don't clobber alu_temp before using it to decide whether to change ea
+ var adjust = alu_temp.Bit(8);
+ alu_temp = _link.ReadMemory((ushort) ea);
- if (alu_temp.Bit(8))
+ if (adjust)
{
- alu_temp = _link.ReadMemory((ushort)ea);
ea = (ushort)(ea + 0x100);
}
- else alu_temp = _link.ReadMemory((ushort)ea);
+ }
+ }
+
+ private void AbsIdx_Stage4_SHX()
+ {
+ rdy_freeze = !RDY;
+
+ if (RDY)
+ {
+ var adjust = alu_temp.Bit(8);
+ alu_temp = _link.ReadMemory((ushort) ea);
+
+ if (adjust)
+ {
+ ea = (ushort) (ea & 0xFF | ((ea + 0x100) & 0xFF00 & (X << 8)));
+ }
+ }
+ }
+
+ private void AbsIdx_Stage4_SHY()
+ {
+ rdy_freeze = !RDY;
+
+ if (RDY)
+ {
+ var adjust = alu_temp.Bit(8);
+ alu_temp = _link.ReadMemory((ushort) ea);
+
+ if (adjust)
+ {
+ ea = (ushort) (ea & 0xFF | ((ea + 0x100) & 0xFF00 & (Y << 8)));
+ }
+ }
+ }
+
+ private void AbsIdx_Stage4_SHA()
+ {
+ rdy_freeze = !RDY;
+
+ if (RDY)
+ {
+ var adjust = alu_temp.Bit(8);
+ alu_temp = _link.ReadMemory((ushort) ea);
+
+ if (adjust)
+ {
+ ea = (ushort) (ea & 0xFF | ((ea + 0x100) & 0xFF00 & ((A & X) << 8)));
+ }
}
}
@@ -2431,16 +2558,38 @@ private void AbsIdx_WRITE_Stage5_STA()
private void AbsIdx_WRITE_Stage5_SHY()
{
- alu_temp = Y & (ea >> 8);
- ea = (ea & 0xFF) | (alu_temp << 8); //"(the bank where the value is stored may be equal to the value stored)" -- more like IS.
- _link.WriteMemory((ushort)ea, (byte)alu_temp);
+ alu_temp = Y;
+
+ if (RDY)
+ {
+ alu_temp &= unchecked((byte)((ea >> 8) + 1));
+ }
+
+ _link.WriteMemory((ushort) ea, (byte) alu_temp);
}
private void AbsIdx_WRITE_Stage5_SHX()
{
- alu_temp = X & (ea >> 8);
- ea = (ea & 0xFF) | (alu_temp << 8); //"(the bank where the value is stored may be equal to the value stored)" -- more like IS.
- _link.WriteMemory((ushort)ea, (byte)alu_temp);
+ alu_temp = X;
+
+ if (RDY)
+ {
+ alu_temp &= unchecked((byte)((ea >> 8) + 1));
+ }
+
+ _link.WriteMemory((ushort) ea, (byte) alu_temp);
+ }
+
+ private void AbsIdx_WRITE_Stage5_SHA()
+ {
+ alu_temp = A & X;
+
+ if (RDY)
+ {
+ alu_temp &= unchecked((byte)((ea >> 8) + 1));
+ }
+
+ _link.WriteMemory((ushort) ea, (byte) alu_temp);
}
private void AbsIdx_WRITE_Stage5_ERROR()
@@ -2921,6 +3070,7 @@ private void ExecuteOneRetry()
case Uop.IndIdx_Stage3: IndIdx_Stage3(); break;
case Uop.IndIdx_Stage4: IndIdx_Stage4(); break;
case Uop.IndIdx_WRITE_Stage5: IndIdx_WRITE_Stage5(); break;
+ case Uop.IndIdx_WRITE_Stage5_SHA: IndIdx_WRITE_Stage5_SHA(); break;
case Uop.IndIdx_READ_Stage5: IndIdx_READ_Stage5(); break;
case Uop.IndIdx_RMW_Stage5: IndIdx_RMW_Stage5(); break;
case Uop.IndIdx_WRITE_Stage6_STA: IndIdx_WRITE_Stage6_STA(); break;
@@ -3021,6 +3171,7 @@ private void ExecuteOneRetry()
case Uop.Imm_LDA: Imm_LDA(); break;
case Uop.Imm_LDX: Imm_LDX(); break;
case Uop.Imm_LDY: Imm_LDY(); break;
+ case Uop.Imm_ANE: Imm_ANE(); break;
case Uop.Imm_Unsupported: Imm_Unsupported(); break;
case Uop.IdxInd_Stage3: IdxInd_Stage3(); break;
case Uop.IdxInd_Stage4: IdxInd_Stage4(); break;
@@ -3071,9 +3222,13 @@ private void ExecuteOneRetry()
case Uop.AbsIdx_Stage3_X: AbsIdx_Stage3_X(); break;
case Uop.AbsIdx_READ_Stage4: AbsIdx_READ_Stage4(); break;
case Uop.AbsIdx_Stage4: AbsIdx_Stage4(); break;
+ case Uop.AbsIdx_Stage4_SHX: AbsIdx_Stage4_SHX(); break;
+ case Uop.AbsIdx_Stage4_SHY: AbsIdx_Stage4_SHY(); break;
+ case Uop.AbsIdx_Stage4_SHA: AbsIdx_Stage4_SHA(); break;
case Uop.AbsIdx_WRITE_Stage5_STA: AbsIdx_WRITE_Stage5_STA(); break;
case Uop.AbsIdx_WRITE_Stage5_SHY: AbsIdx_WRITE_Stage5_SHY(); break;
case Uop.AbsIdx_WRITE_Stage5_SHX: AbsIdx_WRITE_Stage5_SHX(); break;
+ case Uop.AbsIdx_WRITE_Stage5_SHA: AbsIdx_WRITE_Stage5_SHA(); break;
case Uop.AbsIdx_WRITE_Stage5_ERROR: AbsIdx_WRITE_Stage5_ERROR(); break;
case Uop.AbsIdx_RMW_Stage5: AbsIdx_RMW_Stage5(); break;
case Uop.AbsIdx_RMW_Stage7: AbsIdx_RMW_Stage7(); break;
diff --git a/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs b/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs
index 9884a1fcf7e..983dedab51d 100644
--- a/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs
+++ b/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/MOS6502X.cs
@@ -245,6 +245,18 @@ public bool FlagN
private set => P = (byte)((P & ~0x80) | (value ? 0x80 : 0x00));
}
+ ///
+ /// For the unsupported opcode, ANE.
+ /// If your core requires a specific constant for this opcode, set it here.
+ ///
+ public byte AneConstant = 0xFF;
+
+ ///
+ /// For the unsupported opcode, LXA.
+ /// If your core requires a specific constant for this opcode, set it here.
+ ///
+ public byte LxaConstant = 0xFF;
+
public long TotalExecutedCycles;
// SO pin
diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Chip6510.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Chip6510.cs
index 1ff8be0ee5a..038aabcc104 100644
--- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Chip6510.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Chip6510.cs
@@ -51,7 +51,12 @@ public CpuLink(Chip6510 chip)
public Chip6510()
{
// configure cpu r/w
- _cpu = new MOS6502X(new CpuLink(this));
+ _cpu = new MOS6502X(new CpuLink(this))
+ {
+ // Required to pass the Lorenz test suite.
+ AneConstant = 0xEF,
+ LxaConstant = 0xFE
+ };
// perform hard reset
HardReset();
diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs
index b7b4e085fa3..70ceb86a8f5 100644
--- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs
@@ -54,7 +54,9 @@ public Drive1541(int clockNum, int clockDen, Func getCurrentDiskNumber)
DriveRom = new Chip23128();
_cpu = new MOS6502X(new CpuLink(this))
{
- NMI = false
+ NMI = false,
+ AneConstant = 0xEF,
+ LxaConstant = 0xFE
};
_ram = new int[0x800];