Skip to content
Eliott65wiki
Contents

The bus: serving every cycle of the 6502

It all starts here: on every cycle, the 6502 asks for a byte, and the RP2040 must answer in time. How Eliott65 went from 0.3 MHz to 8 MHz, and why the ARM cores no longer take part.

On this page

The problem to solve

On every clock cycle, the 6502 places an address on its pins and waits for a piece of data (a read) or offers one (a write). On the Neo6502kbd, it is the RP2040 that must, within the same cycle:

  1. read the address, in two halves, through two of the buffers;
  2. find the matching byte in the 64 KiB array that acts as the 6502’s memory;
  3. present it through the third buffer, or copy the byte written by the 6502;
  4. produce the edges of the PHI2 clock.

All of this several million times per second, without ever making a mistake or falling behind.

The RP2040’s tools: PIO and DMA

The RP2040 has two PIO blocks: tiny specialised processors that run programs of a few instructions at the pace of the system clock and drive the pins with single-cycle precision. It also has a DMA controller, which copies data from one place in memory to another without occupying the ARM cores.

First version: the PIO and an ARM core (v0.2)

At first start-up, the PIO read the address and passed it to an ARM core, which fetched the byte and handed it back to the PIO. The 6502 started first time: a 52 KiB memory test with no errors, and a correct checksum.

Then it had to go faster. The measurements tell the story:

Setting6502 speed
RP2040 at 125 MHz, cautious PIO≈ 0.3 MHz
PIO at full speed2.0 MHz
RP2040 at 200 MHz3.4 MHz
RP2040 at 252 MHz4.3 MHz
lighter ARM loop, shorter delays6.26 MHz

Beyond that, nothing moved: the round trip between the PIO and the ARM core cost about 40 RP2040 cycles per 6502 cycle. That was the bottleneck.

What the datasheet really says

One question kept coming up: “doesn’t this 6502 go up to 14 MHz?” The WDC datasheet is clear. The 14 MHz is guaranteed at 5 V. At 3.3 V, the board’s voltage, the guarantee is 8 MHz, with clock phases of at least 62 ns.

Yet our 6.26 MHz setting left a low phase of only 16 to 32 ns: it worked, but out of specification. The tests also showed that the real limit came from the 6502 itself: it needs about 32 ns after the clock falls to present a valid address.

Hence the rule from then on: read the address during the low phase, serve the data during the high phase, as the datasheet describes.

How fast can this chip really go?

A separate test bench measured the limit of our specimen: the PIO alone answers NOP to every read, and the frequency rises in steps until it fails.

  • This 6502 runs at 10.5 MHz at least at 3.3 V, well beyond the guaranteed 8 MHz.
  • What makes it fail is not the frequency, but the width of the high phase: 12 ns works, 8 ns fails, even at low speed.

The bench only tests reads of NOP: writes and complex instructions still had to be validated with the real bus.

The current version: PIO + DMA, without an ARM core (v0.3)

Eliott65’s bus no longer involves any ARM core. For each cycle:

  1. during the low phase, the PIO reads the address and builds a small transfer descriptor (where to copy from, where to copy to);
  2. a first DMA channel copies this descriptor into the configuration of a second channel;
  3. the second channel transfers one byte: from the 6502’s memory to the PIO for a read, from the PIO to memory for a write; then it re-arms the first.
One 6502 bus cycleDuring the low phase of the PHI2 clock, the PIO reads the address on the eight shared wires, in two halves. During the high phase, the DMA serves the data to the 6502 or copies it into its memory. A cycle lasts about 133 nanoseconds at 7.5 MHz.PHI2low phasehigh phaseGPIO 0–7address A0–A7address A8–A15data D0–D7: served or receivedthe PIO reads the address(at least ≈ 32 ns after the falling edge)the DMA copies the bytefrom or to the 6502's memoryOne cycle ≈ 133 ns at 7.5 MHz (TURBO mode); no ARM core on the path
A bus cycle: the address is read in the low phase, the data served or received in the high phase. The DMA delays fit into the high phase, since the 6502 only reads the data when the clock falls.

A trick makes writes possible: to copy “the value d” with a DMA that can only copy from addresses, Eliott65 keeps a 256-byte table in which byte number d holds d. Copying from the address table + d means copying the value d.

First try on the board: everything works. And both ARM cores are now free, one for the kernel, the other for video.

The speed modes

The PIO delays are set at compile time. Three settings are offered:

ModeMeasured speedWhat it guarantees
SPEC6.48 MHzfollows the WDC datasheet to the letter
TURBO (default)7.52 MHza one-cycle margin on the measured limit
MAX8.00 MHzat the limit, with no margin

Beyond that, two failures were observed, each with its own cause: at 8.50 MHz the address is read too early, at 8.37 MHz the data arrives too late before the clock falls.

These figures were measured at 252 MHz. At 270 MHz, the same delays run faster: the 6502 measured 7.72 MHz with video on (v0.52.0), then 7.707 MHz with the margin added below (v0.59.1).

270 MHz: a margin that vanishes (v0.52.1)

After the move to 270 MHz, a fault appeared on the board: the GRAPHE demo stops calling the kernel after a few minutes. The 6502 still runs, but does nothing useful any more; once, the USB hub counted 10 devices instead of 4. Cause unknown at first.

With no board for the next session, the investigation was done on the emulator’s bus model. The model first reproduces the known measurements at 252 MHz (the settings that pass and those that fail), then it is pushed to 270 MHz, constraint by constraint. Only one loses its margin: the switching of the 74LVC245 buffers that separate address and data on the board.

  • The firmware leaves 4 cycles after the switch before reading the address. The measurements at 252 MHz put the switching time of these buffers between 11.9 and 15.9 ns.
  • At 270 MHz, 4 cycles are only 14.8 ns: if this board’s buffers are slow, an address is read wrong from time to time.
  • Candidate fix: one more cycle above 252 MHz (18.5 ns). Predicted cost: about 3%, i.e. 7.49 MHz instead of 7.72, still faster than at 252 MHz.

On the board (v0.59.1). The fix is in the flashed firmware, and the 6502 measures 7.707 MHz (three matching measurements). The real cost is only 0.1 %, against 2.9 % predicted: we don’t know why the model overestimates this cost. The emulator was re-calibrated on this measurement. GRAPHE now runs under the watch of the wireless probe, which reads the number of kernel calls by itself every second and will freeze the machine’s state if it stops moving: the result is not yet known.

Measuring without seeing the cycles go by

A small puzzle: how do you count cycles when no core sees them any more? A hardware counter wired to the clock pin sees nothing, since the pin belongs to the PIO. The solution chosen: an extra PIO state machine follows the clock and counts down, and core 1 reads its counter.

To go further: System calls, which rely on the same mechanism.

Sources in the repository : docs/journal/03-bus-demarrage.md, docs/journal/04-performances.md, docs/adr/ADR-0006-bus-pio-dma.md, docs/adr/ADR-0005-overclocking.md, docs/adr/ADR-0027-signal-unique-720x480.md.