6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Apr 27, 2024 2:31 pm

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: Fri Jul 01, 2022 4:46 pm 
Offline

Joined: Fri Jul 01, 2022 6:33 am
Posts: 4
So I was quite happy about my 6502 emu. And then I started comparing logs with visual6502/perfect6502. Aaaand... no.

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:
start:
  ldx #$02
loop:
  dex
  nop
  bne loop
  sta $20
  dey
  jmp start


Assembled listing:

Code:
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


My first confusion happens already while executing the first two instructions. Here's the log from perfect6502, with my comments/questions embedded. Note that the status is printed before each half-cycle is executed:

Code:
; 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


While writing this, I was hoping for some "rubber ducking" effect to take place, but nope, I'm still as confused as before.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 01, 2022 6:24 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10793
Location: England
Welcome! I'm having trouble accessing visual6502 but I have a local copy (you could download one from the Wayback Machine.) I'm not so familiar with perfect6502 - the model is fine, I'm sure, but I don't know about the inputs or the interpreting of the logs

Here's your test program running in visual6502:
Code:
cycle ab   db   rw   Fetch    pc    a    x    y    s   p
 0   0000   a2   1   LDX #   0000   aa   00   00   fd   nv‑BdIZc
 0   0000   a2   1   LDX #   0000   aa   00   00   fd   nv‑BdIZc
 1   0001   02   1           0001   aa   00   00   fd   nv‑BdIZc
 1   0001   02   1           0001   aa   00   00   fd   nv‑BdIZc
 2   0002   ca   1   DEX     0002   aa   02   00   fd   nv‑BdIzc
 2   0002   ca   1   DEX     0002   aa   02   00   fd   nv‑BdIzc
 3   0003   ea   1           0003   aa   02   00   fd   nv‑BdIzc
 3   0003   ea   1           0003   aa   02   00   fd   nv‑BdIzc
 4   0003   ea   1   NOP     0003   aa   02   00   fd   nv‑BdIzc
 4   0003   ea   1   NOP     0003   aa   02   00   fd   nv‑BdIzc
 5   0004   d0   1           0004   aa   01   00   fd   nv‑BdIzc
 5   0004   d0   1           0004   aa   01   00   fd   nv‑BdIzc
 6   0004   d0   1   BNE     0004   aa   01   00   fd   nv‑BdIzc
 6   0004   d0   1   BNE     0004   aa   01   00   fd   nv‑BdIzc
 7   0005   fc   1           0005   aa   01   00   fd   nv‑BdIzc
 7   0005   fc   1           0005   aa   01   00   fd   nv‑BdIzc
 8   0006   85   1           0006   aa   01   00   fd   nv‑BdIzc
 8   0006   85   1           0006   aa   01   00   fd   nv‑BdIzc
 9   0002   ca   1   DEX     0002   aa   01   00   fd   nv‑BdIzc
 9   0002   ca   1   DEX     0002   aa   01   00   fd   nv‑BdIzc
10   0003   ea   1           0003   aa   01   00   fd   nv‑BdIzc
10   0003   ea   1           0003   aa   01   00   fd   nv‑BdIzc
11   0003   ea   1   NOP     0003   aa   01   00   fd   nv‑BdIzc
11   0003   ea   1   NOP     0003   aa   01   00   fd   nv‑BdIzc
12   0004   d0   1           0004   aa   00   00   fd   nv‑BdIZc
12   0004   d0   1           0004   aa   00   00   fd   nv‑BdIZc
13   0004   d0   1   BNE     0004   aa   00   00   fd   nv‑BdIZc
13   0004   d0   1   BNE     0004   aa   00   00   fd   nv‑BdIZc
14   0005   fc   1           0005   aa   00   00   fd   nv‑BdIZc
14   0005   fc   1           0005   aa   00   00   fd   nv‑BdIZc
15   0006   85   1   STA zp  0006   aa   00   00   fd   nv‑BdIZc
15   0006   85   1   STA zp  0006   aa   00   00   fd   nv‑BdIZc
16   0007   20   1           0007   aa   00   00   fd   nv‑BdIZc
16   0007   20   1           0007   aa   00   00   fd   nv‑BdIZc
17   0020   20   0           0008   aa   00   00   fd   nv‑BdIZc
17   0020   aa   0           0008   aa   00   00   fd   nv‑BdIZc
18   0008   88   1   DEY     0008   aa   00   00   fd   nv‑BdIZc
18   0008   88   1   DEY     0008   aa   00   00   fd   nv‑BdIZc
19   0009   4c   1           0009   aa   00   00   fd   nv‑BdIZc
19   0009   4c   1           0009   aa   00   00   fd   nv‑BdIZc
20   0009   4c   1   JMP Abs 0009   aa   00   00   fd   nv‑BdIZc
20   0009   4c   1   JMP Abs 0009   aa   00   00   fd   nv‑BdIZc
21   000a   00   1           000a   aa   00   ff   fd   Nv‑BdIzc
21   000a   00   1           000a   aa   00   ff   fd   Nv‑BdIzc
22   000b   00   1           000b   aa   00   ff   fd   Nv‑BdIzc
22   000b   00   1           000b   aa   00   ff   fd   Nv‑BdIzc
23   0000   a2   1   LDX #   0000   aa   00   ff   fd   Nv‑BdIzc
23   0000   a2   1   LDX #   0000   aa   00   ff   fd   Nv‑BdIzc


To get the pairings of the half-cycles right, perhaps easiest to look at the RnW line going low for a write. But I would expect the address bus also to be a good indication. (It's possible this just isn't so for perfect6502.)

Note that the updated value of X from the LDA is first seen in the next cycle after the value appears on the bus.

But also note that the update of X from DEX is seen in the second cycle of the NOP: the decrement is done during the first cycle of NOP, and the write to X happens at the end of that first cycle, so it is first seen in the second cycle. This is because the ALU is needed and that takes a cycle to operate.

If you feel you might get lost, add sync to your traced signals.

I think I'd also add the alu inputs and outputs:
logmore=sync,alua,alub,alu

The way I think of it
- in a sync cycle, the 6502 is fetching the opcode, which arrives in the final nanoseconds. There's nothing it can do which is opcode specific, even though this is commonly counted as the first cycle.
- in the next cycle, the 6502 was already committed to reading the operand, whether or not there will be one, as it had no idea what it was going to need to do. In this cycle, it decodes the opcode and sets up the action for the following cycle. It also figures out if the next cycle needs to be the next sync
- in the third cycle, finally the 6502 can take an opcode-specific action. And it might be the next sync, or a fetch of a third byte, or something else.

Hope this helps - happy to discuss. If you have a single specific question that might be best - we can deal with each question as it comes up.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 01, 2022 6:58 pm 
Offline

Joined: Sat Feb 19, 2022 10:14 pm
Posts: 147
When I started out with the 65C02 I never knew this existed, but Table 5-7 of the WDC 65816 datasheet lists what is on the address and data buses during each clock cycle. I've found this helpful in understanding what's going on as each instruction is executed. I don't think it's fully applicable to the 65C02, but I've used the 8-bit cycles from this table in working with the 65C02 more recently. The 65816 does differ from the 65C02 in cycle timing so this probably isn't perfect in all cases.

If anyone knows of a similar table specific for the 65C02, I'd appreciate a link.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 01, 2022 8:04 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
tmr4 wrote:
When I started out with the 65C02 I never knew this existed, but Table 5-7 of the WDC 65816 datasheet lists what is on the address and data buses during each clock cycle.  I've found this helpful in understanding what's going on as each instruction is executed.  I don't think it's fully applicable to the 65C02, but I've used the 8-bit cycles from this table in working with the 65C02 more recently.  The 65816 does differ from the 65C02 in cycle timing so this probably isn't perfect in all cases.

If anyone knows of a similar table specific for the 65C02, I'd appreciate a link.

I've been able to get most of the information I needed from the footnotes and the later section on caveats.  At the beginning of the footnotes, it says, "Be aware that notes #4-7, 9 and 10 apply to the W65C02S and W65C816S.  All other notes apply to the W65C816S only."
Attachment:
65cycleNotes.gif
65cycleNotes.gif [ 61.61 KiB | Viewed 6686 times ]

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 01, 2022 8:13 pm 
Offline

Joined: Fri Jul 01, 2022 6:33 am
Posts: 4
BigEd wrote:
Welcome! I'm having trouble accessing visual6502 but I have a local copy (you could download one from the Wayback Machine.) I'm not so familiar with perfect6502 - the model is fine, I'm sure, but I don't know about the inputs or the interpreting of the logs


I've compared visual6502 and perfect6502, and they produce identical result. Pro with perfect6502 is that I could easily modify it to run from the command line and output whatever log I needed. With visual6502 I had to run a few cycles in the browser and copy the table for further adjustments. A con with perfect6502 is that it does not seem to easily allow logging of sync for example. Need to investigate a bit more. Anyway, either work!

One difference is that visual6502 happily starts at 0. I had to "trick" perfect6502 into doing that, using the reset vector. As far as I can see, half-cycles 0+0 in your visual6502 is equal to half-cycle 0+1 in my perfect6502 log (except the registers are not initialized with same values, for whatever reason...).

BigEd wrote:
Note that the updated value of X from the LDA is first seen in the next cycle after the value appears on the bus.


Yes. This is what I would expect:

- Cycle 0: read opcode
- Cycle 1: read value and set x
- Cycle 2: first state with the new x

This is what I would expect from an operation documented to take 2 cycles, and the cycles correspond to what cpu_6502.txt says about immediate addressing.

BigEd wrote:
But also note that the update of X from DEX is seen in the second cycle of the NOP: the decrement is done during the first cycle of NOP, and the write to X happens at the end of that first cycle, so it is first seen in the second cycle. This is because the ALU is needed and that takes a cycle to operate.


Uhm, this is where it gets strange. Implied addressing mode operations should take 2 cycles to execute, the same as LDX. This is according to both cpu_6502.txt and the W65C02S data sheet (table 4-1). But according to the log, it actually takes three cycles:

- Cycle 0: read opcode
- Cycle 1: (nothing...)
- Cycle 2: decrement X + read next op into IR
- Cycle 3: the first state with a new, decremented X value

Now, I understand that this does not really affect anything, as by the time the next operation can do something with X, it will always be decremented and ready. And it only consumes 2 cycles, as when the third cycle is running, the first cycle of the next operation executes in parallel. Could this be the reason why it's not documented?

This does however make it more complicated to compare logs between my emulator and perfect6502/visual6502. I could of course investigate every type of operation with the great tools we now have, but that's a lot of work!

BigEd wrote:
If you feel you might get lost, add sync to your traced signals.

I think I'd also add the alu inputs and outputs:
logmore=sync,alua,alub,alu


That's great! Will do that for future logs!


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 01, 2022 8:19 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10793
Location: England
[Sorry, wrote this just prior to your reply. Hope it helps]

One way to look at this: from the programmer's perspective, we can simply say that LDX immediate, or DEX, takes two cycles. And several places tabulate the cycles, just in case one wishes to look one level deeper and see what the bus is doing on each cycles.

I'm pretty sure this level of abstraction is sufficient, to write a cycle accurate model of the externally visible behaviour.

And then there's another perspective, which goes deeper, which is about how the 6502 is implemented internally, and that's what you can see with visual6502 or perfect6502. Some of what you learn here might be useful if you were making a cycle-accurate HDL model.

But I think what's going on with the head post is some difficulty in reconciling the external perspective and the internal perspective. There's nothing going on which can't be understood, but it's operating at a different level.

In particular, you can't tell from outside which cycle it is that DEX causes the X register to get the new value. All you can tell from outside is what you can get from a program, and the program is going to pick up the value after it's written - because of the internal sequence of events.

As I say, keep an eye on SYNC. That's when the external observer starts counting cycles - and therefore, it's where the external observer stops worrying about the previous instruction. The internal machinery may still have further work to do.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 01, 2022 8:20 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10793
Location: England
So, although DEX might take three cycles to get its job done (or even four), that's of no interest to any external observer or any program: the next instruction will be fetched after two cycles. Conventionally, and usefully, we say that DEX is a two cycle instruction.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 02, 2022 9:33 pm 
Offline

Joined: Fri Jul 01, 2022 6:33 am
Posts: 4
Thanks BigEd, this was just the response I needed to get some confidence in how I interpret the logs and documentation! I'm sure more questions will pop up shortly! :)


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 08, 2022 2:13 pm 
Offline
User avatar

Joined: Fri Jun 22, 2012 7:39 am
Posts: 201
Try Breaks Debugger: viewtopic.php?f=8&t=6973

https://github.com/emu-russia/breaks/re ... s-debug-18

There's a tab that shows what's going on at the bottom of the processor.

_________________
6502 addict


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 09, 2022 9:07 pm 
Offline

Joined: Fri Jul 01, 2022 6:33 am
Posts: 4
I ran into this strange behavior of the BIT operation. The BIT operation does two things:

Quote:
Bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V);
The zero-flag is set to the result of operand AND accumulator.


I'm still trying to get my emu to pass Klaus tests, and I'm running perfect6502 in parallel for comparison.

So what I've found is that the two tasks of the BIT operation seems to happen in two cycles, but not always. Here's the first BIT operation:

Code:
; BIT cycle 0
; Read opcode
halfcyc:192600 phi0:0 AB:1B75 D:00 RnW:1 PC:1B75 A:FF X:00 Y:FF SP:FF P:10 IR:28  <--- sync
halfcyc:192601 phi0:1 AB:1B75 D:24 RnW:1 PC:1B75 A:FF X:00 Y:FF SP:FF P:10 IR:28 R$1B75=$24

; BIT cycle 1
; Read pointer
halfcyc:192602 phi0:0 AB:1B76 D:24 RnW:1 PC:1B76 A:FF X:00 Y:FF SP:FF P:10 IR:24
halfcyc:192603 phi0:1 AB:1B76 D:18 RnW:1 PC:1B76 A:FF X:00 Y:FF SP:FF P:10 IR:24 R$1B76=$18

; BIT cycle 2
; Read from the address
halfcyc:192604 phi0:0 AB:0018 D:18 RnW:1 PC:1B77 A:FF X:00 Y:FF SP:FF P:10 IR:24
halfcyc:192605 phi0:1 AB:0018 D:00 RnW:1 PC:1B77 A:FF X:00 Y:FF SP:FF P:10 IR:24 R$0018=$00

; BIT cycle 3
; Operand is $00, A is $FF, P is $10.
; - Bit 7 and 6 of operand are transferred to P. No change in P.
; - Operand ($00) AND accumulator ($FF) is zero, so zero flag is set: P is $12.
halfcyc:192606 phi0:0 AB:1B77 D:00 RnW:1 PC:1B77 A:FF X:00 Y:FF SP:FF P:12 IR:24  <--- sync
halfcyc:192607 phi0:1 AB:1B77 D:08 RnW:1 PC:1B77 A:FF X:00 Y:FF SP:FF P:12 IR:24 R$1B77=$08

; No more changes from the BIT operation ...
halfcyc:192608 phi0:0 AB:1B78 D:08 RnW:1 PC:1B78 A:FF X:00 Y:FF SP:FF P:12 IR:08
halfcyc:192609 phi0:1 AB:1B78 D:C9 RnW:1 PC:1B78 A:FF X:00 Y:FF SP:FF P:12 IR:08 R$1B78=$C9

halfcyc:192610 phi0:0 AB:01FF D:C9 RnW:0 PC:1B78 A:FF X:00 Y:FF SP:FF P:12 IR:08
halfcyc:192611 phi0:1 AB:01FF D:32 RnW:0 PC:1B78 A:FF X:00 Y:FF SP:FF P:12 IR:08 W$01FF=$32

halfcyc:192612 phi0:0 AB:1B78 D:C9 RnW:1 PC:1B78 A:FF X:00 Y:FF SP:FE P:12 IR:08
halfcyc:192613 phi0:1 AB:1B78 D:C9 RnW:1 PC:1B78 A:FF X:00 Y:FF SP:FE P:12 IR:08 R$1B78=$C9


But then, some cycles later, another BIT operation takes place. Same addressing mode, but what happens in cycle 3 and 4 differs:

Code:
; BIT cycle 0
; Read opcode
halfcyc:192744 phi0:0 AB:1B9D D:00 RnW:1 PC:1B9D A:01 X:00 Y:FF SP:FF P:10 IR:28  <--- sync
halfcyc:192745 phi0:1 AB:1B9D D:24 RnW:1 PC:1B9D A:01 X:00 Y:FF SP:FF P:10 IR:28 R$1B9D=$24

; BIT cycle 1
; Read pointer
halfcyc:192746 phi0:0 AB:1B9E D:24 RnW:1 PC:1B9E A:01 X:00 Y:FF SP:FF P:10 IR:24
halfcyc:192747 phi0:1 AB:1B9E D:16 RnW:1 PC:1B9E A:01 X:00 Y:FF SP:FF P:10 IR:24 R$1B9E=$16

; BIT cycle 2
; Read from the address
halfcyc:192748 phi0:0 AB:0016 D:16 RnW:1 PC:1B9F A:01 X:00 Y:FF SP:FF P:10 IR:24
halfcyc:192749 phi0:1 AB:0016 D:82 RnW:1 PC:1B9F A:01 X:00 Y:FF SP:FF P:10 IR:24 R$0016=$82

; BIT cycle 3
; Operand is $82, A is $01, P is $10.
; Compare this and the next cycle with the equivalent above:
; P changes to $90 in this cycle
halfcyc:192750 phi0:0 AB:1B9F D:82 RnW:1 PC:1B9F A:01 X:00 Y:FF SP:FF P:90 IR:24  <--- sync
halfcyc:192751 phi0:1 AB:1B9F D:08 RnW:1 PC:1B9F A:01 X:00 Y:FF SP:FF P:90 IR:24 R$1B9F=$08

; BIT cycle 4
; ... and then it changes to $92 in this cycle
halfcyc:192752 phi0:0 AB:1BA0 D:08 RnW:1 PC:1BA0 A:01 X:00 Y:FF SP:FF P:92 IR:08
halfcyc:192753 phi0:1 AB:1BA0 D:C9 RnW:1 PC:1BA0 A:01 X:00 Y:FF SP:FF P:92 IR:08 R$1BA0=$C9

; No more changes from the BIT operation ...
halfcyc:192754 phi0:0 AB:01FF D:C9 RnW:0 PC:1BA0 A:01 X:00 Y:FF SP:FF P:92 IR:08
halfcyc:192755 phi0:1 AB:01FF D:B2 RnW:0 PC:1BA0 A:01 X:00 Y:FF SP:FF P:92 IR:08 W$01FF=$B2

halfcyc:192756 phi0:0 AB:1BA0 D:C9 RnW:1 PC:1BA0 A:01 X:00 Y:FF SP:FE P:92 IR:08
halfcyc:192757 phi0:1 AB:1BA0 D:C9 RnW:1 PC:1BA0 A:01 X:00 Y:FF SP:FE P:92 IR:08 R$1BA0=$C9

halfcyc:192758 phi0:0 AB:1BA1 D:C9 RnW:1 PC:1BA1 A:01 X:00 Y:FF SP:FE P:92 IR:C9
halfcyc:192759 phi0:1 AB:1BA1 D:01 RnW:1 PC:1BA1 A:01 X:00 Y:FF SP:FE P:92 IR:C9 R$1BA1=$01


I can't see why the two operations differ in execution. I understand that it makes no difference from the outside for the same reason as discussed above: the P register will be correct by the time the next operation can do anything with it.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 09, 2022 9:22 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10793
Location: England
I think what's happening is because Z is set according to an internal bus value - and in the case where one of the operands is a zero, that zero is setting Z. The result of the AND, one cycle later, will also set Z, in the same cycle that it would (and should) anyway, but you can no longer see it because Z has already been set.

In effect, the value of Z in cycle 3 is a don't care, and so the implementation challenge of whether or not to set Z in cycle 3 is also a don't care.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 25, 2023 2:20 pm 
Offline
User avatar

Joined: Sat Dec 01, 2018 1:53 pm
Posts: 727
Location: Tokyo, Japan
tmr4 wrote:
When I started out with the 65C02 I never knew this existed, but Table 5-7 of the WDC 65816 datasheet lists what is on the address and data buses during each clock cycle....
If anyone knows of a similar table specific for the 65C02, I'd appreciate a link.

I don't know of one for the 65C02 offhand, but MOS supplied something similar for the 6502 in the original in Appendix E of the 1976 MCS6500 Microcomputer Family Programming Manual.

_________________
Curt J. Sampson - github.com/0cjs


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: