I found this document (reproduced below and I added some '[*]' references) at
http://www.textfiles.com/programming/6502bugs.txt . For some reason it made me want to argue with the author.
[1] these quirks are pretty well documented
[2] I ran this bit of code in Micromon. Sure enough, that's what it does. It also seems to force the unused bit 5 "-" flag to 1 (NV-B DIZC)
1000 LDA #$00
1002 PHA
1003 PLP
1004 PHP
1005 PLA
1006 STA $1010
1009 BRK
: 1010 30
But then I disassembled the ROM IRQ entry point, and the value of the B flag is tested there, from the copy stored on the stack
E442 PHA
E443 TXA
E444 PHA
E445 TYA
E446 PHA
E447 TSX
E448 LDA $0104,X
E44B AND #$10
E44D BEQ $E452
E44F JMP ($0092)
E452 JMP ($0090)
So I wrote an IRQ handler and vectored to it
1020 TSX
1021 LDA $0104,X
1024 STA $1010
1027 PHP
1028 PLA
1029 STA $1011
102C JMP $6355
Inspecting those two memory locations revealed that the value of P pushed by the hardware IRQ has the B bit off, with the unused flag in bit5 still on
: 1010 23 35
[3] Nonsense. It's all documented here:
http://6502.org/tutorials/decimal_mode.html
[4] Yep. Very annoying.
[5] Interesting writeup here:
http://www.pagetable.com/?p=45 . I don't know of too many pre-1977 6502 chips out there in the wild, so this is a non-issue. I wonder what happens when the pre-1977 6502 encounters the $6A $66 $76 $6E or $7E opcodes?
[6] What are they talking about here? Is there any way to predict what this "garbage address" might be?
[7] Simple. Go to Radio Shack and hook up a pushbutton switch to pin 38 of your 6502 chip. Connect the other side to ground. Now every time you push the button, a SEV instruction will be executed. Not very useful, except in the Commodore 1541 disk drive ROM where it was used to detect bits flying by on the diskette where IRQ wasn't fast enough.
[8] Twice as fast is unlikely, since the fastest 6502 instructions all take two clock cycles and so do immediate addressing mode instructions.
--
With all the books on 6502 programming, and all the years that the 6502 has
been around and popular, you'd think that any quirks would have been well
documented by now. But nooooo!
So... for those of you involved in assembler or machine-language programming,
here are some 6502 booby-traps -- those marked with * are supposedly fixed
in the CMOS parts such as 65C02 and 65C102 (but not the C-64's 6510).
---------
o Return address pushed on the stack by JSR is one less than actual next
instruction. RTS increments PC after popping. RTI doesn't. [1]
o The status bits pushed on the stack by PHP have the breakpoint bit set. [2]
o *The D (decimal mode) flag is not defined after RESET. [1]
o *The D (decimal mode) flag is not cleared by interrupts. [1]
o *The ADC and SBC instructions don't set N,V, and Z status bits if decimal
mode is on. C status is set correctly. [3]
o *An indirect JMP (xxFF) will fail because the MSB will be fetched from
address xx00 instead of page xx+1. [4]
o *If an interrupt occurs on a BRK instruction, the breakpoint is ignored. [1]
o *The ROR instruction didn't exist in the very earliest (pre-'77) chips. [5]
o *Undefined op-codes do strange things, some lock up the CPU. [1]
Unlike most microprocessors, the 6502 does not make memory accesses on an
"as needed" basis. It always does a fetch or store on every single clock
cycle. There are a few cases, though, where there isn't anything to be
fetched or stored, and a "garbage" fetch or store occurs. This is mainly
of importance with the memory-mapped I/O devices:
o *When adding a carry to the MSB of an address, a fetch occurs at a garbage
address. The CMOS chips refetch the last byte of the instruction. [6]
o *When doing a fetch-modify-store instruction (INC, DEC, ASL, LSR, ROL,
ROR) garbage is stored into the location during the "modify" cycle...
followed by the "real" store cycle which stores the correct data. The
CMOS chips do a second fetch instead of a garbage store.
These aren't really "bugs", but there are some instructions that just seem
like they ought to be there, but aren't:
o *INC A and DEC A.
o *BRA relative. Unconditional branch.
o *BIT #immediate. The CMOS chips also have BIT absolute,X and
BIT zeropage,X.
o STX absolute,Y and STY absolute,X. How come LDX and LDY can use these
addressing modes, but the matching store instructions can't?
o SEV. Set overflow bit. Probably not really useful, but you can set and
clear all of the other status bits, and there *is* a CLV. [7]
o Personally, I'd also like to have "Clear A" and "Test A" instructions.
These would be twice as fast [8] and half as big as LDA #0 and CMP #0.
Ironically, the CMOS chips have an STZ (Store Zero) instruction which
can clear a memory location, but still can't clear the Accumulator.
o I'd also like to have BSR relative. A subroutine call that's relocatable.
*Fixed in the CMOS versions (65C02, 65C102, etc.)
-------------------------------------------------------------------------------