6502 cycle-level instruction detail

discuss bbc micro and electron emulators (including mame) here!
Post Reply
Coeus
Posts: 1821
Joined: Mon Jul 25, 2016 12:05 pm
Contact:

6502 cycle-level instruction detail

Post by Coeus » Thu Oct 15, 2020 2:34 pm

Tables of opcodes and their cycle counts are readily available for the various members of the 6502 family but is there any straightforward documentation available as to what the cycles that make up that instruction actually do?

I know there is visual 6502 which goes down to transistor level but that is a bit too low-level.

I note, for example, that the 65816 emulation in B-em, cribbed from snes, fetches the byte after the opcode even for instructions whose addressing mode is implied. Assuming this matches the real hardware this is at least a partial explanation as to why, prior to the CMOS versions, the minimum clock cycle count for any instruction was two. I am also sure I read a description, possibly of interrupt or reset handling, where two variations were produced, not by omitting an unnecessary clock cycle but by forcing it to do a read rather than a write.

So I was thinking something like this, for the ROR absolute,x instruction, 7 cycles, with my guesswork:
  1. Fetch opcode
  2. Fetch low byte of address
  3. Fetch high byte of address
  4. Add X to address
  5. Fetch operand from address
  6. Perform rotation
  7. Write result back to address

User avatar
BigEd
Posts: 3450
Joined: Sun Jan 24, 2010 10:24 am
Location: West
Contact:

Re: 6502 cycle-level instruction detail

Post by BigEd » Thu Oct 15, 2020 2:58 pm

I don't know of a cycle-tabulation for 65816 - the question came up only yesterday, and Dave (hoglet) discovered that JSR's cycles are different in the 816 compared to the 02.

For the '02, there's
http://nesdev.com/6502_cpu.txt
(and certainly others too: see this thread.)

User avatar
BigEd
Posts: 3450
Joined: Sun Jan 24, 2010 10:24 am
Location: West
Contact:

Re: 6502 cycle-level instruction detail

Post by BigEd » Thu Oct 15, 2020 3:29 pm

Oh hang on, found this which covers 6502 and 65816, cycle by cycle:
https://the-dreams.de/aay64.txt

tom_seddon
Posts: 426
Joined: Tue Aug 30, 2005 12:42 am
Contact:

Re: 6502 cycle-level instruction detail

Post by tom_seddon » Thu Oct 15, 2020 3:40 pm

The Synertek 6502 hardware manual (there's a copy on 6502.org) has tables at the back for the bus accesses for each type of instruction.

--Tom

User avatar
SarahWalker
Posts: 1313
Joined: Fri Jan 14, 2005 3:56 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by SarahWalker » Thu Oct 15, 2020 5:02 pm

I used to use 64doc.txt for cycle details. Very outdated now though, and it only really covered the NMOS chips.

Coeus
Posts: 1821
Joined: Mon Jul 25, 2016 12:05 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by Coeus » Thu Oct 15, 2020 5:07 pm

Thanks, everyone. Very interesting reading.

User avatar
Rich Talbot-Watkins
Posts: 1662
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: 6502 cycle-level instruction detail

Post by Rich Talbot-Watkins » Sat Oct 17, 2020 8:05 pm

In the particular example you gave (ROR abs,x), here's how the cycles break down. Let's say we're executing ROR &32F0,X with X=&28.

- Fetch opcode ROR abs,X, increment PC *

- Fetch low byte of address (&F0), increment PC
- Fetch high byte of address (&32), add X to low byte without carry, increment PC
- Fetch data from &3218, add carry into high byte
- Fetch data from &3318, i.e. with carry
- Store data back to &3318, perform rotate, check pending interrupts
- Store modified data back to &3318
- Fetch next opcode, increment PC *

* if an interrupt has previously been determined as pending, during opcode fetch it will begin interrupt dispatch instead of incrementing PC

When emulating 'tricky' stuff like Kevin Edwards' Nightshade protection, it's important to get all these details right, particularly the extra store of the unmodified data which can cause significant interaction between the hardware and the 6502 interrupt dispatch.

^ This specifically applies to NMOS 6502; CMOS 6502 is different, and I have no idea about the 16-bit cousins.

dominicbeesley
Posts: 1163
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by dominicbeesley » Sun Oct 18, 2020 1:56 pm

I've been too ill to concentrate on much the past couple of days but I was looking at this https://www.google.com/url?sa=t&source= ... rVfWqn6unK

Table 6.7 has the bus cycles laid out. I seem to recall there being a similar thing for the wdc65c02 as well. Not sure how these compare with othe c02 chips. In theory the 65816 should be the same as nmos in emulation mode for legal instructions?

D

User avatar
hoglet
Posts: 9449
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: 6502 cycle-level instruction detail

Post by hoglet » Sun Oct 18, 2020 2:40 pm

dominicbeesley wrote:
Sun Oct 18, 2020 1:56 pm
In theory the 65816 should be the same as nmos in emulation mode for legal instructions?
If you mean the cycle-by-cycle use of the bus, then no, they do not appear to be identical.

JSR is definitely different:

Code: Select all

6502 / 65C02:
    <opcode> <op1> <read dummy> <write pch> <write pcl> <op2>

65C816:
    <opcode> <op1> <op2> <read dummy> <write pch> <write pcl> 

There are other cycle time differences that trip up my 6502 Decoder (in syncless mode).

Dave

Coeus
Posts: 1821
Joined: Mon Jul 25, 2016 12:05 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by Coeus » Mon Oct 19, 2020 1:40 am

hoglet wrote:
Sun Oct 18, 2020 2:40 pm
65C816:
<opcode> <op1> <op2> <read dummy> <write pch> <write pcl>
I think the order has been changed here to make the instruction abortable. There is talk in the data sheet about virtual memory (though I don't remember if that's what they called it) so hardware external to the processor has to be able to check the destination address and abort the instruction if necessary before the instruction has had any effect, i.e. before pushing the return address onto the stack.

In the original 6502 order is odd, expect that the byte after the opcode is always read anyway. Then pushing the return address next avoids the need to have a temporary register to store the other half of the destination address - that can be read directly into the PC.

On the question of the 65816 being more like the NMOS or CMOS 6502, that data sheet was for a 65C816 - was there ever an NMOS 65816? The one described in the data sheet seems more like the 65C02 but the emulation mode doesn't implement the Rockwell instructions.

User avatar
hoglet
Posts: 9449
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: 6502 cycle-level instruction detail

Post by hoglet » Mon Oct 19, 2020 7:11 am

Coeus wrote:
Mon Oct 19, 2020 1:40 am
[In the original 6502 order is odd, expect that the byte after the opcode is always read anyway. Then pushing the return address next avoids the need to have a temporary register to store the other half of the destination address - that can be read directly into the PC.
BBR/BBS also have an unusual cycle pattern.

Code: Select all

      // Example: BBR0, $50, +6
      // 0 8f 1 1 1 <opcode>
      // 1 50 1 0 1 <op1> i.e. ZP address
      // 2 01 1 0 1 <mem rd>
      // 3 01 1 0 1 <mem rd>
      // 4 06 1 0 1 <op2> i.e.
      // 5 20 1 0 1 (<branch taken penalty>)
      // 6          (<page crossed penalty>)
But these instructions don't exist on the 65C816.
Coeus wrote:
Mon Oct 19, 2020 1:40 am
On the question of the 65816 being more like the NMOS or CMOS 6502, that data sheet was for a 65C816 - was there ever an NMOS 65816? The one described in the data sheet seems more like the 65C02 but the emulation mode doesn't implement the Rockwell instructions.
No, I don't think there ever was an NMOS 65816.

Dave

dominicbeesley
Posts: 1163
Joined: Tue Apr 30, 2013 12:16 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by dominicbeesley » Mon Oct 19, 2020 11:41 am

I guess I'd read this and taken it to heart
When the 65816 and 65802 are powered on, they initialize themselves into 6502 emulation mode in
which, with the exception of fixing several 6502 bugs, they exactly emulate the 6502. The stack is confined to
page one, just like the 6502 stack pointer. The registers are configured to eight bits, to model the 6502’s
registers. Every 6502 instruction is implemented identically. The timing of each instruction is exactly the same
as on the original NMOS 6502.
Taken from "Programming the 65816", David Eyes and Ron Lichty, The Western Design Center, Inc.

Are you working on a 65816 mode for the decoder Dave? I keep starting but haven't found the time to progress it much.

D

ThomasHarte
Posts: 513
Joined: Sat Dec 23, 2000 5:56 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by ThomasHarte » Mon Oct 19, 2020 12:34 pm

Having just implemented it myself, the full 65816 cycle-by-cycle steps are in its data sheet — check out Page 42 onwards.

Also note that fhe “identical except for bug fixes caveat” is quite a caveat. Not only is JMP (xxxx) fixed so as not to be page-constrained, which they’d also fixed on the 65C02, but abs, [x/y] and the second part of (direct), y don’t wrap by bank (i.e. the computed address can be in the next 64kb subdivision).

That said, there is a special case of single-byte wrapping in indexed direct mode if you’re in emulation mode and the low byte of the direct register is 0. So somebody has been very specific about permitted deviations.

Oh, and for my 65816 emulation I transcribed every example from this page into a unit test, which was a huge help. There’s otherwise only exactly one minor piece of test code that I’m aware of, which is Jeek816 that is in the VICE repository. That tests that four or five addressing modes wrap appropriately where a deficiency had been found in VICE but not anything else. Though it is actual 65816 code that switches into and out of emulation mode, so it helped a lot with very early testing.

User avatar
BigEd
Posts: 3450
Joined: Sun Jan 24, 2010 10:24 am
Location: West
Contact:

Re: 6502 cycle-level instruction detail

Post by BigEd » Mon Oct 19, 2020 12:43 pm

Hi Thomas - that unit test from Bruce's document sounds great. Have you put it online?

ThomasHarte
Posts: 513
Joined: Sat Dec 23, 2000 5:56 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by ThomasHarte » Mon Oct 19, 2020 2:16 pm

Yes, but it probably won't be useful because I wrote it as native code rather than emulated — specifically it's in Swift, e.g.

Code: Select all

func testDirectIndirectLong() {
	// "If the D register is $FF00 and the m flag is 0, then for LDA [$FE], the
	// address of the low byte of the pointer is $00FFFE, the address of the middle
	// byte is $00FFFF, and the address of the high byte is $000000. Furthermore, if
	//	* $000000 contains $12
	//	* $00FFFE contains $FF
	//	* $00FFFF contains $FF
	// then LDA [$FE] loads the low byte of the data from address $12FFFF, and the
	// high byte from $130000."
	let machine = machine16()

	machine.setValue(0xff00, for: .direct)

	machine.setValue(0x12, forAddress: 0x0000)
	machine.setValue(0xff, forAddress: 0xfffe)
	machine.setValue(0xff, forAddress: 0xffff)

	machine.setValue(0xab, forAddress: 0x12ffff)
	machine.setValue(0xcd, forAddress: 0x130000)

	// LDA [$fe]; NOP
	machine.setData(Data([0xa7, 0xfe, 0xea]), atAddress: 0x0200)

	machine.setValue(0x200, for: .programCounter)
	machine.runForNumber(ofCycles: 8)

	XCTAssertEqual(machine.value(for: .A), 0xcdab)
}
And one other quirk worth mentioning is that each runs the test machine for one cycle longer than the actual instruction length, running into the [usually; I wasn't that careful about e.g. BRK] NOP that follows because my emulation won't actually complete the LDA or whatever until the cycle after the bus activity has ended. So in the example above I actually expect LDA [$fe] to take seven cycles.

I otherwise found that:
  • AllSuiteA doesn't work on a 65816 as it tests invalid opcodes;
  • Klaus Dormann's regular 6502 test works correctly, but his 65C02 test doesn't because it tests BBR, BBS, etc, which the 65816 doesn't implement; and
  • of course, Wolfgang Lorenz's tests are broken down by opcode and addressing mode so you can just use the appropriate subset of those. Though unfortunately that doesn't include ADC and SBC because the 65816 sets the N flag in decimal mode like the 65C02 does based on the final result, and not based on the intermediate result after only the low nibble has been corrected as per the 6502.
Also in case it's interesting the emulation itself, which is in C++, is here with the interesting bits being the breakdown of addressing modes into internal micro-ops here and the interpreter for those micro-ops here.

Bugs may still lurk. As well as the more formal tests I've plugged it into my emulated Oric and found what you'd sort of expect — old software tends to work, modern software sometimes doesn't, probably correlating with the wide resources now available for the unofficial opcodes. I'm about to embark on my first machine that actually uses a 65816.

EDIT: and, yeah, all that signalling of whether the thing being fetched is an opcode, program, data, vector or internal operation looks like I'm planning for poor coupling but is actually information the 65816 exposes. You can see it implied by the VPA, VPD and VPL lines in the tables in the data sheet, I just turned it into an enum. It's a really weird chip in net in my opinion. It's still doing the 6502 thing of memory-instead-of-registers, but now it's loading and storing 16-bit values across an 8-bit bus and it even has a memory lock line because obviously you'd want to build a multiprocessor system like that. Though in fairness maybe it was more to allow a 65816 to be an IO helper while serving a more capable boss.

User avatar
BigEd
Posts: 3450
Joined: Sun Jan 24, 2010 10:24 am
Location: West
Contact:

Re: 6502 cycle-level instruction detail

Post by BigEd » Mon Oct 19, 2020 2:59 pm

Thanks for the details! I did once wonder about - and may even have started - trying to convert Bruce's examples into code. But I certainly didn't finish, so well done. And although Swift won't be the language in use by every project, surely the intent of each testcase is now simply translatable to implementation in a language of choice.

The '816 certainly hasn't lived up to my initial hopes. But I think my position now is that when approached with care it can be a useful upgrade to a 6502, either incrementally or as a system overhaul.

Coeus
Posts: 1821
Joined: Mon Jul 25, 2016 12:05 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by Coeus » Mon Oct 19, 2020 3:34 pm

ThomasHarte wrote:
Mon Oct 19, 2020 2:16 pm
[*] Klaus Dormann's regular 6502 test works correctly, but his 65C02 test doesn't because it tests BBR, BBS, etc, which the 65816 doesn't implement;
As supplied pre-assembled, yes, but testing of the Rockwell instructions is a conditional assembly option.

ThomasHarte
Posts: 513
Joined: Sat Dec 23, 2000 5:56 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by ThomasHarte » Mon Oct 19, 2020 4:24 pm

Coeus wrote:
Mon Oct 19, 2020 3:34 pm
ThomasHarte wrote:
Mon Oct 19, 2020 2:16 pm
[*] Klaus Dormann's regular 6502 test works correctly, but his 65C02 test doesn't because it tests BBR, BBS, etc, which the 65816 doesn't implement;
As supplied pre-assembled, yes, but testing of the Rockwell instructions is a conditional assembly option.
You're completely right, and here is the proof.

User avatar
hoglet
Posts: 9449
Joined: Sat Oct 13, 2012 7:21 pm
Location: Bristol
Contact:

Re: 6502 cycle-level instruction detail

Post by hoglet » Mon Oct 19, 2020 5:46 pm

dominicbeesley wrote:
Mon Oct 19, 2020 11:41 am
Are you working on a 65816 mode for the decoder Dave? I keep starting but haven't found the time to progress it much.
All I've done so far is add an 816 mode that adjusts the expected cycle behavious of JSR.

This was enough to solve my immediate need.

It would be good to have this support the complete 65816.

It's a shame the code is such a mess!

ThomasHarte
Posts: 513
Joined: Sat Dec 23, 2000 5:56 pm
Contact:

Re: 6502 cycle-level instruction detail

Post by ThomasHarte » Tue Oct 20, 2020 12:25 am

So, I grabbed Dormann's repository and a copy of DOSBox in order to be able to run his preferred assembler, made appropriate edits, and the attached should be his 65C02 tests restricted to the appropriate subset for a 65816 — i.e. no Rockwell/WDC BBR, BBS, RMB & SMB, no testing that all the undefined opcodes are NOPs.

It's in exactly the same form as the binaries he otherwise provides; a 64kb image in which you should start the PC at $400 and keep going until the code starts JMPing to the same address. If that JMP is at $11e0 then you passed, otherwise the problem is as implied by whatever you find in the .lst.

I found a couple more issues in my 65816* so this was already worthwhile. Having fixed those, the test fully passed so I'm fairly confident I built the proper thing.

* having TRB direct bound as a second copy of TRB absolute, and not clearing the decimal flag upon BRK.
Attachments
65C02_no_Rockwell_test.zip
(35.6 KiB) Not downloaded yet

Post Reply

Return to “8-bit acorn emulators”