예제 #1
0
        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));
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        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));
        }
예제 #4
0
        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);
        }
예제 #5
0
        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));
        }
예제 #6
0
        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));
        }
예제 #7
0
 private void ChangeMos6502State(Mos6502State newState)
 {
     _logger.LogTrace(new EventId(0, "ChangingMos6502State"), "Changing state from {OldMos6502State} to {NewMos6502State}", CurrentState, newState);
     CurrentState = newState;
 }
예제 #8
0
 public Mos6502Cpu(Mos6502State initialState, MemoryUnit memory) : this(initialState, memory, NullLoggerFactory.Instance)
 {
 }
예제 #9
0
 private static Mos6502State Arr(int address, Mos6502State currentState, MemoryUnit memory)
 {
     throw new NotImplementedException();
 }