Back when dinosaurs roamed the earth, the method for DMC-safe controller reading was either to continually reread until two consecutive reads match, or to read a fixed amount of times and pick out a matching pair of reads, falling back to the previous frame's controller state if there's none. There's potentially another way to do it.
Bits have two possible states, so if you have three bits, you're guaranteed a matching pair of values somewhere among those three bits. If you fetch 3 controller status bytes, you should be able to build a new controller status byte by finding the matching pair for each bit, using the three bytes.
The truth table to apply to each bit is this:
The logic for that is: (A & (B | C)) | (B & C)
If you read the controller three times and store each byte in A, B, and C, the 6502 code to do a bitwise "sock pairing" is this:
A is only needed once, so it can double as the result byte. Assuming zeropage, this code is 24 cycles, plus the time it takes to do 3 full reads of the controller port, which should be fixed time as well. The advantage of doing it this way versus a 3-way byte-comparing way is that the single frame latency for a failed matchmaking is localized to each individual button of the controller, rather than all buttons.
Edit: One caveat is, because of the possible latency with the individual bits, there are extremely extremely extremely rare situations where a DMC glitch can happen right as you shift your thumb on the d-pad to another direction, to cause the software to see both up+down or both left+right pressed simultaneously. For instance, one byte of left pressed, one byte of right pressed, and a DMC-glitched byte of right pressed that looks like left+right are pressed; the pairing algorithm will see two 1's for left and two 1's for right, giving the software one frame of left+right. This requires an extremely specific case of everything being timed perfectly, and may be just as rare as a real controller physically having left+right pressed.
Bits have two possible states, so if you have three bits, you're guaranteed a matching pair of values somewhere among those three bits. If you fetch 3 controller status bytes, you should be able to build a new controller status byte by finding the matching pair for each bit, using the three bytes.
The truth table to apply to each bit is this:
Code:
A B C
0 0 0 | 0
0 0 1 | 0
0 1 0 | 0
0 1 1 | 1
1 0 0 | 0
1 0 1 | 1
1 1 0 | 1
1 1 1 | 1
0 0 0 | 0
0 0 1 | 0
0 1 0 | 0
0 1 1 | 1
1 0 0 | 0
1 0 1 | 1
1 1 0 | 1
1 1 1 | 1
The logic for that is: (A & (B | C)) | (B & C)
If you read the controller three times and store each byte in A, B, and C, the 6502 code to do a bitwise "sock pairing" is this:
Code:
lda B
ora C
and A
sta A
lda B
and C
ora A
sta A
ora C
and A
sta A
lda B
and C
ora A
sta A
A is only needed once, so it can double as the result byte. Assuming zeropage, this code is 24 cycles, plus the time it takes to do 3 full reads of the controller port, which should be fixed time as well. The advantage of doing it this way versus a 3-way byte-comparing way is that the single frame latency for a failed matchmaking is localized to each individual button of the controller, rather than all buttons.
Edit: One caveat is, because of the possible latency with the individual bits, there are extremely extremely extremely rare situations where a DMC glitch can happen right as you shift your thumb on the d-pad to another direction, to cause the software to see both up+down or both left+right pressed simultaneously. For instance, one byte of left pressed, one byte of right pressed, and a DMC-glitched byte of right pressed that looks like left+right are pressed; the pairing algorithm will see two 1's for left and two 1's for right, giving the software one frame of left+right. This requires an extremely specific case of everything being timed perfectly, and may be just as rare as a real controller physically having left+right pressed.