MOS Technology 6502 series processor.
Compatible with:
- 6502
- 6510
- 8502
The program counter on the 6502 increments before fetching the opcode, not after. To run code starting at address $400, the PC needs to be set to $3ff. This kept confusing me when switching between this processor and the Z80 which does not have this behavior. The solution is to obtain the address of the next instruction using cpu.PC() + cpu.Offset()
. On the Z80, Offset returns 0 but on the 6502 returns 1.
All these years I thought there was a break flag on the processor but apparently that is not true. The only time this is "seen" is during a brk
instruction. When the status register is pushed to the stack in this case, bit 4, the so-called break flag, is set. I implemented the brk
instruction wrong at least twice. The correct implementation, after decoding the opcode, appears to be:
- fetch another byte which is discarded
- push the value of the PC + 1 to the stack
- push the value of the status register with bit 5 set.
- disable interrupts
- set the PC to the value found at 0xfffe - 1
When pushing the status register to the stack using the php
instruction, ensure that both bits 4 and 5 are set. The plp
instruction needs to make sure that bit 4, if set, is cleared when it is transfered to the status register.
In this implementation the status register is a variable. In other implementaitons I made it a getter and setter function. To ensure bit 5 is always set and that bit 4 is always clear, those operations are applied after each instruction is executed.
c.push(c.SR | FlagB | Flag5)
tsx
modifies the N and Z flags.txs
does not modify any flags.
The reference I was using did not mention anything about the flags for these operations.
Unit tests were written when the 6502 emulator was developed to try and catch as many cases as possible but it has gaps in coverage. This provides a good quick first test to make sure the code is running as expected.
For full coverage, the tests written by Klaus Dormann from the 6502_65C02_functional_tests repository are used.
The assembly code for running these tests are not found in the repository. Download bin_files/6502_functional_test.bin
and place it in a ~/rcs/ext/m6502
directory. Run the tests by using the build tag ext
.
- Butterfield, Jim, "Machine Language for the Commodore 64, 128, and Other Commodore Computers. Revised and Expanded Edition", https://archive.org/details/Machine_Language_for_the_Commodore_Revised_and_Expanded_Edition
- Clark, Bruce, "Decimal Mode", http://www.6502.org/tutorials/decimal_mode.html
- Dormann, Klaus, "Tests for all valid opcodes of the 6502 and 65C02 processor", https://github.com/Klaus2m5/6502_65C02_functional_tests
- Pickens, John, et al. "NMOS 6502 Opcodes", http://www.6502.org/tutorials/6502opcodes.html
- "Status Flags", https://wiki.nesdev.com/w/index.php/Status_flags
- Steil, Michael, "Internals of BRK/IRQ/NMI/RESET on a MOS 6502", https://www.pagetable.com/?p=410