private static Mos6502State Asl(int address, Mos6502State currentState, MemoryUnit memory) { var operand = address == 0 ? currentState.A : memory.ReadByte(address); var r = operand << 1; var flags = currentState.P; flags = flags.SetIf(r > 0xFF, Mos6502Flags.Carry); r = (byte)r; // Set Zero flag **only** if the accumulator changes to zero. if (address == 0) { flags = flags.SetIf(r == 0, Mos6502Flags.Zero); } flags = flags.SetIf((r & 0b1000_0000) != 0, Mos6502Flags.Negative); if (address == 0) { return(currentState.With(a: (byte)r, p: flags)); } else { memory.WriteByte(address, (byte)r); return(currentState.With(p: flags)); } }
public Mos6502Cpu(Mos6502State initialState, MemoryUnit memory, ILoggerFactory loggerFactory) { CurrentState = initialState; Memory = memory; _logger = loggerFactory.CreateLogger <Mos6502Cpu>(); _logger.LogTrace(new EventId(0, "Initializing"), "Initializing with state: {InitialMos6502State}", CurrentState); }
private static Mos6502State And(int address, Mos6502State currentState, MemoryUnit memory) { var value = memory.ReadByte(address); var r = (byte)(value & currentState.A); var flags = currentState.P; flags = flags.SetIf(r == 0, Mos6502Flags.Zero); flags = flags.SetIf((r & 0b1000_0000) != 0, Mos6502Flags.Negative); return(currentState.With(a: r, p: flags)); }
private static Mos6502State Ahx(int address, Mos6502State currentState, MemoryUnit memory) { // AHX is an unofficial opcode with odd behavior // Based this test on https://github.com/anurse/remy/blob/4f01c0e16ac9b8db1553d97588c9d8927884cef1/src/hw/mos6502/exec/store.rs#L158 // I don't remember where I figured that behavior out then :(. var highByte = (address & 0xFF00) >> 8; var val = currentState.A & currentState.X & highByte; memory.WriteByte(address, (byte)val); return(currentState); }
private static Mos6502State Bit(int address, Mos6502State currentState, MemoryUnit memory) { var m = memory.ReadByte(address); var result = currentState.A & m; var flags = currentState.P; flags = flags.SetIf(result == 0, Mos6502Flags.Zero); flags = flags.SetIf((result & 0b0100_0000) != 0, Mos6502Flags.Overflow); flags = flags.SetIf((result & 0b1000_0000) != 0, Mos6502Flags.Negative); return(currentState.With(p: flags)); }
private static Mos6502State Adc(int address, Mos6502State currentState, MemoryUnit memory) { // ADC: A = A + M + P[Carry] var m = memory.ReadByte(address); var r = currentState.A + m + (int)(currentState.P & Mos6502Flags.Carry); var flags = currentState.P; // Carry out if r overflows flags = flags.SetIf(r > 0xFF, Mos6502Flags.Carry); r = (byte)r; flags = flags.SetIf(r == 0, Mos6502Flags.Zero); flags = flags.SetIf((r & 0b1000_0000) != 0, Mos6502Flags.Negative); // Check if the overflow bit should be set. // The bit should be set when both A and M have the same sign bit, and R has a different sign bit. // This indicates that signed addition overflowed and the sign bit is inaccurate. // We set based on this truth table // | # | A | M | R | A ^ M | A ^ R | Value | // | 1 | 0b0xxx_xxxx | 0b0xxx_xxxx | 0b0xxx_xxxx | 0b0xxx_xxxx | 0b0xxx_xxxx | F | // | 2 | 0b0xxx_xxxx | 0b0xxx_xxxx | 0b1xxx_xxxx | 0b0xxx_xxxx | 0b1xxx_xxxx | T | // | 3 | 0b0xxx_xxxx | 0b1xxx_xxxx | 0b0xxx_xxxx | 0b1xxx_xxxx | 0b0xxx_xxxx | F | // | 4 | 0b0xxx_xxxx | 0b1xxx_xxxx | 0b1xxx_xxxx | 0b1xxx_xxxx | 0b1xxx_xxxx | F | // | 5 | 0b1xxx_xxxx | 0b0xxx_xxxx | 0b0xxx_xxxx | 0b1xxx_xxxx | 0b1xxx_xxxx | F | // | 6 | 0b1xxx_xxxx | 0b0xxx_xxxx | 0b1xxx_xxxx | 0b1xxx_xxxx | 0b0xxx_xxxx | F | // | 7 | 0b1xxx_xxxx | 0b1xxx_xxxx | 0b0xxx_xxxx | 0b0xxx_xxxx | 0b1xxx_xxxx | T | // | 8 | 0b1xxx_xxxx | 0b1xxx_xxxx | 0b1xxx_xxxx | 0b0xxx_xxxx | 0b0xxx_xxxx | F | // From the above, we can see that overflow is set in rows 2 and 7, when: // * A^M has the sign bit clear // * AND, A^R has the sign bit set. flags = ((currentState.A ^ m) & 0x80) == 0 && ((currentState.A ^ r) & 0x80) == 0x80 ? flags | Mos6502Flags.Overflow : flags & ~Mos6502Flags.Overflow; return(currentState.With(a: r, p: flags)); }
private void ChangeMos6502State(Mos6502State newState) { _logger.LogTrace(new EventId(0, "ChangingMos6502State"), "Changing state from {OldMos6502State} to {NewMos6502State}", CurrentState, newState); CurrentState = newState; }
public Mos6502Cpu(Mos6502State initialState, MemoryUnit memory) : this(initialState, memory, NullLoggerFactory.Instance) { }
private static Mos6502State Arr(int address, Mos6502State currentState, MemoryUnit memory) { throw new NotImplementedException(); }