It's something about the "pipelining" that just breaks my brain. At least I think it's related to that.
For testing, I created a very small program:
Code: Select all
start:
ldx #$02
loop:
dex
nop
bne loop
sta $20
dey
jmp start
Code: Select all
0000 START
0000 A2 02 LDX #$02
0002 LOOP
0002 CA DEX
0003 EA NOP
0004 D0 FC BNE $0002
0006 85 20 STA $20
0008 88 DEY
0009 4C 00 00 JMP $0000
Code: Select all
; Reset sequence. I've so far not attempted to get this right in my emulator, so I'm skipping
; these cycles for now.
halfcyc:0 phi0:1 AB:00FF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00 R$00FF=$00
halfcyc:1 phi0:0 AB:00FF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00
halfcyc:2 phi0:1 AB:00FF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00 R$00FF=$00
halfcyc:3 phi0:0 AB:00FF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00
halfcyc:4 phi0:1 AB:00FF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00 R$00FF=$00
halfcyc:5 phi0:0 AB:00FF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00
halfcyc:6 phi0:1 AB:00FF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00 R$00FF=$00
halfcyc:7 phi0:0 AB:01C0 D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00
halfcyc:8 phi0:1 AB:01C0 D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00 R$01C0=$00
halfcyc:9 phi0:0 AB:01BF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00
halfcyc:10 phi0:1 AB:01BF D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00 R$01BF=$00
halfcyc:11 phi0:0 AB:01BE D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00
halfcyc:12 phi0:1 AB:01BE D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:C0 P:02 IR:00 R$01BE=$00
halfcyc:13 phi0:0 AB:FFFC D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:BD P:02 IR:00
halfcyc:14 phi0:1 AB:FFFC D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:BD P:06 IR:00 R$FFFC=$00
halfcyc:15 phi0:0 AB:FFFD D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:BD P:16 IR:00
halfcyc:16 phi0:1 AB:FFFD D:00 RnW:1 PC:00FF A:00 X:C0 Y:00 SP:BD P:16 IR:00 R$FFFD=$00
; I've reset the half-cycle count, as this is the first cycle that has PC set to the start address (0).
;
; Reflection:
; As I understand it, AB is the address bus, and D is what's been buffered from the data bus.
; In comparison, visual6502 shows both "db" and "pd". I assume that "db" is the state of the
; data pins, while "pd" is what's been buffered, as visual6502 has value A2 for "db" already
; in half-cycle 0.
;
; Question:
; What would you consider a "full cycle"? Is it half-cycle 0+1, or 1+2? 0+1 makes sense to
; me as it allows the address bus to be set in the first half-cycle, and data pins to be valid in
; the second half-cycle.
;
; But on the other hand, 17 half-cycles have been executed before reaching this point,
; so it means that the reset sequence would have added one extra half-cycle.
;
; I will group the half-cycles below based on my assumption above.
;
; Based on what happens in the next cycle, I think we're in the first cycle of
; the LDX operation here ("fetch opcode"). See next comment.
halfcyc:0 phi0:0 AB:0000 D:00 RnW:1 PC:0000 A:00 X:C0 Y:00 SP:BD P:16 IR:00
halfcyc:1 phi0:1 AB:0000 D:A2 RnW:1 PC:0000 A:00 X:C0 Y:00 SP:BD P:16 IR:00 R$0000=$A2
; This is the first cycle where IR is A2 ("LDX #$02"). So the opcode has already been fetched.
; Because of that I assume this means that we're in the second cycle of "LDX"? The
; assumption is based on the well-known 6502_cpu.txt, which documents the cycles
; of this operation like this:
;
; Immediate addressing
;
; # address R/W description
; --- ------- --- ------------------------------------------
; 1 PC R fetch opcode, increment PC
; 2 PC R fetch value, increment PC <--- we're here
;
; Note that X is untouched.
halfcyc:2 phi0:0 AB:0001 D:A2 RnW:1 PC:0001 A:00 X:C0 Y:00 SP:BD P:16 IR:A2
halfcyc:3 phi0:1 AB:0001 D:02 RnW:1 PC:0001 A:00 X:C0 Y:00 SP:BD P:16 IR:A2 R$0001=$02
; When this cycle is about to be executed, X has been set to 2 by the LDX instruction. From this, I assume
; that X is set during "halfcyc 3" above, and is ready when this cycle begins.
;
; I assume that no pre-fetch was made during the execution of LDX, since the last cycle of LDX requires
; a bus read. This means we're at cycle 1 of DEX:
;
; Accumulator or implied addressing
;
; # address R/W description
; --- ------- --- -----------------------------------------------
; 1 PC R fetch opcode, increment PC <--- we're here
; 2 PC R read next instruction byte (and throw it away)
;
halfcyc:4 phi0:0 AB:0002 D:02 RnW:1 PC:0002 A:00 X:02 Y:00 SP:BD P:14 IR:A2
halfcyc:5 phi0:1 AB:0002 D:CA RnW:1 PC:0002 A:00 X:02 Y:00 SP:BD P:14 IR:A2 R$0002=$CA
; Nothing interesting here. Next instruction byte is read. Not sure why it's thrown away?
halfcyc:6 phi0:0 AB:0003 D:CA RnW:1 PC:0003 A:00 X:02 Y:00 SP:BD P:14 IR:CA
halfcyc:7 phi0:1 AB:0003 D:EA RnW:1 PC:0003 A:00 X:02 Y:00 SP:BD P:14 IR:CA R$0003=$EA
; What? Third cycle of DEX? There should be no such, and X is still not decremented.
halfcyc:8 phi0:0 AB:0003 D:EA RnW:1 PC:0003 A:00 X:02 Y:00 SP:BD P:14 IR:CA
halfcyc:9 phi0:1 AB:0003 D:EA RnW:1 PC:0003 A:00 X:02 Y:00 SP:BD P:14 IR:CA R$0003=$EA
; Finally, X is decremented.
; As IR is already NOP, and as this operation has the same addressing mode as DEX,
; I assume this means we're at cycle 2 of the NOP.
halfcyc:10 phi0:0 AB:0004 D:EA RnW:1 PC:0004 A:00 X:01 Y:00 SP:BD P:14 IR:EA
halfcyc:11 phi0:1 AB:0004 D:D0 RnW:1 PC:0004 A:00 X:01 Y:00 SP:BD P:14 IR:EA R$0004=$D0
; Nothing changes here. I include some more cycles, but will not comment on them,
; as I think the above is enough to get started.
halfcyc:12 phi0:0 AB:0004 D:D0 RnW:1 PC:0004 A:00 X:01 Y:00 SP:BD P:14 IR:EA
halfcyc:13 phi0:1 AB:0004 D:D0 RnW:1 PC:0004 A:00 X:01 Y:00 SP:BD P:14 IR:EA R$0004=$D0
halfcyc:14 phi0:0 AB:0005 D:D0 RnW:1 PC:0005 A:00 X:01 Y:00 SP:BD P:14 IR:D0
halfcyc:15 phi0:1 AB:0005 D:FC RnW:1 PC:0005 A:00 X:01 Y:00 SP:BD P:14 IR:D0 R$0005=$FC
halfcyc:16 phi0:0 AB:0006 D:FC RnW:1 PC:0006 A:00 X:01 Y:00 SP:BD P:14 IR:D0
halfcyc:17 phi0:1 AB:0006 D:85 RnW:1 PC:0006 A:00 X:01 Y:00 SP:BD P:14 IR:D0 R$0006=$85
halfcyc:18 phi0:0 AB:0002 D:85 RnW:1 PC:0002 A:00 X:01 Y:00 SP:BD P:14 IR:D0
halfcyc:19 phi0:1 AB:0002 D:CA RnW:1 PC:0002 A:00 X:01 Y:00 SP:BD P:14 IR:D0 R$0002=$CA
halfcyc:20 phi0:0 AB:0003 D:CA RnW:1 PC:0003 A:00 X:01 Y:00 SP:BD P:14 IR:CA
halfcyc:21 phi0:1 AB:0003 D:EA RnW:1 PC:0003 A:00 X:01 Y:00 SP:BD P:14 IR:CA R$0003=$EA
halfcyc:22 phi0:0 AB:0003 D:EA RnW:1 PC:0003 A:00 X:01 Y:00 SP:BD P:14 IR:CA
halfcyc:23 phi0:1 AB:0003 D:EA RnW:1 PC:0003 A:00 X:01 Y:00 SP:BD P:14 IR:CA R$0003=$EA