Assembly quick reference
Numbers: $D020 hex, %10110000 binary, 42 decimal, 'A' character. Labels end in :. Constants: NAME = expr. Origin: *= $0400 or .org. Expressions take + and -, * means the current address, and </> take the low/high byte.
LDA #$01 — immediate
LDA $D0 — zero page
LDA $D0,X — zero page,X
LDX $D0,Y — zero page,Y
LDA $0400 — absolute
LDA $0400,X — absolute,X
LDA $0400,Y — absolute,Y
LDA ($02,X) — indexed indirect
LDA ($02),Y — indirect indexed
JMP ($FFFC) — indirect
ASL A — accumulator
BNE loop — relative.byte 1, $ff, %1010
.word $0400, label
.text "RAW ASCII"
.screen "SCREEN CODES"
.fill 40, 32
Directives write bytes at the
current address. .screen
converts text to the codes
the VIC actually displays,
so it is what you poke into
$0400.
A label named DONE gets a debugger breakpoint automatically. The reset vector at $FFFC is filled with the first origin unless your source writes it.
Model & limitations
Instruction-level emulation: each instruction completes in one go and then the clock advances by that instruction's cycle count. Real 6510 bus cycles, the pipelined opcode fetch, and cycle-exact VIC badlines are not modelled, so a raster loop here drifts from a real machine.
All 151 documented opcodes plus the stable undocumented ones: SLO RLA SRE RRA SAX LAX DCP ISC ANC ALR ARR SBX LAS, the undocumented NOPs and SBC $EB. Cycle counts include page-cross and branch penalties. The JMP ($xxFF) page-wrap bug, zero-page index wrap, and decimal-mode ADC/SBC all behave as they do on the real chip. JAM halts, as it should.
The unstable opcodes ANE LXA SHA SHX SHY TAS depend on analog behaviour that varies between chips: they decode, then stop the machine rather than invent a value.
Because there is no KERNAL, nothing clears the screen at reset, so this page does it instead: screen RAM starts full of spaces and colour RAM light blue. Everything else in memory starts at zero.
No KERNAL, BASIC, or character ROM ships with this page — those are Commodore copyright. So there is nothing to JSR $FFD2 into, and the character set is an original 8×8 approximation of the C64 uppercase font, not the character ROM. 64 KB of RAM is always underneath.
VIC-II: screen RAM, colour RAM, $D011/$D012 raster (PAL, 63 cycles per line, 312 lines), $D018 screen base, $D020/$D021 colours, and $D011 bit 4 blanking. The border and background colours are remembered for each raster line as the clock advances, so a program that rewrites them mid-frame draws real bars — but the whole character is still fetched at once, so nothing finer than a colour change per line will show. Stepping backwards does not rewind those bars; they redraw on the next pass. No sprites, no bitmap or multicolour modes, no raster interrupts. SID and both CIAs are absent: reads return $FF, writes go nowhere. There are no interrupts at all, so RTI only matters if you push a frame yourself.
Keyboard: Space run/pause, S step, B back, R reset. Shortcuts are inactive inside controls. Back undoes up to 512 instructions.