The NES’s processor: all 256 opcodes, the undocumented ones too, each with its cycle count. Write a little assembly below and step through it.
256 opcodes · ~4 KB gzipped · ~60× a real NES · 244 opcodes checked against SingleStepTests
The smallest loop there is: X from 10 to 0. Watch Z set when X reaches zero, and the branch stop being taken.
Source — edit it
6 bytes at $8000In memory — disassembled
click a line for a breakpoint- loop:
Run at
- A
- $00
- 0 · 00000000
- X
- $00
- 0 · 00000000
- Y
- $00
- 0 · 00000000
- S
- $FA
- 250 · 11111010
- PC
- $8000
Flags — P = $24
N0V0-1B0D0I1Z0C0
- 7
- cycles
- 0
- instructions
Next
LDX #$0A
$A2 · immediate · 2 bytes · 2 cycles
A real NES runs 1,789,773 cycles a second.
Memory
Zero page: the fastest RAM to reach — one-byte addresses, and pointers for ($nn),Y.
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| $0000 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0010 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0020 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0030 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0040 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0050 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0060 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0070 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0080 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $0090 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $00A0 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $00B0 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $00C0 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $00D0 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $00E0 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
| $00F0 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
yellow — written by the last step
All 256 opcodes
151 documented, 105 undocumented — all of them run. The next instruction is lit.
BRKORAJAMSLONOPORAASLSLOPHPORAASLANCNOPORAASLSLOBPLORAJAMSLONOPORAASLSLOCLCORANOPSLONOPORAASLSLOJSRANDJAMRLABITANDROLRLAPLPANDROLANCBITANDROLRLABMIANDJAMRLANOPANDROLRLASECANDNOPRLANOPANDROLRLARTIEORJAMSRENOPEORLSRSREPHAEORLSRALRJMPEORLSRSREBVCEORJAMSRENOPEORLSRSRECLIEORNOPSRENOPEORLSRSRERTSADCJAMRRANOPADCRORRRAPLAADCRORARRJMPADCRORRRABVSADCJAMRRANOPADCRORRRASEIADCNOPRRANOPADCRORRRANOPSTANOPSAXSTYSTASTXSAXDEYNOPTXAANESTYSTASTXSAXBCCSTAJAMSHASTYSTASTXSAXTYASTATXSTASSHYSTASHXSHALDYLDALDXLAXLDYLDALDXLAXTAYLDATAXLXALDYLDALDXLAXBCSLDAJAMLAXLDYLDALDXLAXCLVLDATSXLASLDYLDALDXLAXCPYCMPNOPDCPCPYCMPDECDCPINYCMPDEXSBXCPYCMPDECDCPBNECMPJAMDCPNOPCMPDECDCPCLDCMPNOPDCPNOPCMPDECDCPCPXSBCNOPISCCPXSBCINCISCINXSBCNOPSBCCPXSBCINCISCBEQSBCJAMISCNOPSBCINCISCSEDSBCNOPISCNOPSBCINCISC
How fast, here
Half a second of a tight loop — loads, adds, stores, shifts, branches — on the library, in your browser.
Use it
import { Cpu6502, disassemble } from '@xromdev/cpu6502';
const memory = new Uint8Array(0x10000);
memory.set([0xa2, 0x0a, 0xca, 0xd0, 0xfd, 0x00], 0x8000); // LDX #10 / DEX / BNE / BRK
memory[0xfffc] = 0x00;
memory[0xfffd] = 0x80; // reset vector → $8000
// The bus is yours: memory-mapped hardware is a read or a write that does something.
const cpu = new Cpu6502({
read: (address) => memory[address],
write: (address, value) => { memory[address] = value; },
});
cpu.reset();
while (memory[cpu.pc] !== 0x00) cpu.step(); // step() returns the cycles it took
console.log(cpu.x, cpu.cycles);
console.log(disassemble(memory.subarray(0x8000, 0x8006), 0x8000));