Skip to content

✍️ 필사 모드: Retro Computing for Modern Devs — 6502, Z80, Emulators, and the Lost Joy of Debugging (a 2026 deep-dive on the craft) (english)

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

Prologue — why 6502 in 2026

You probably spent today debugging a React Server Component, tracing which code ran in which runtime, asking yourself "is this running on the server? the client? both? the edge?" and not getting a clean answer. Or your Kubernetes Pod got OOMKilled and you couldn't say exactly which memory page went where, so you doubled the memory limit and went home.

Retro computing is the opposite world.

  • 64 KB of address space. You can know where every byte goes. In fact you have to.
  • 1.79 MHz CPU. You learn how many cycles each instruction takes. Cycle counting is debugging.
  • Two interrupts, total. NMI and IRQ. That is your entire concurrency model.
  • The video chip lives in a separate address space. The PPU. You write the protocol yourself.
  • Compiles in one second. No build cache. No bundler. No dependency graph.

This is the best hobby a modern developer can pick up in 2026, both as a learning tool and as weekend joy. The reason is simple — every leak in every modern abstraction reduces to a problem retro programmers dealt with daily. Memory alignment, cache lines, DMA, interrupt priority, resource contention. The developer who has wrestled with these on an 8-bit machine debugs differently from the one who has not.

And honestly — it is fun. Yes, the days when a single polygon took five seconds to draw are gone, but the feeling of tuning an NMI handler so a sprite appears on exactly the right scanline is still there. Small screen, big constraints, total control over every byte. That kind of joy got lost in the SaaS era.

What we cover:

  1. The hardware — 6502, Z80, 8086 architecture and why it teaches well
  2. The modern retro toolchain — cc65, GBDK, CA65, SDCC, z88dk
  3. The debuggers — Mesen, bgb, bsnes-plus, FCEUX time-travel and memory views
  4. Fantasy consoles — PICO-8, TIC-80, LIKO-12. Why "fantasy" and why a renaissance
  5. The communities — NESDev, AtariAge, GBADev, Pouet, the demoscene
  6. The first weekend project — a hands-on 12-hour "your first 6502 ROM"
  7. The grown-up excuse — why this helps your day job (and why it is fine if it does not)

1. Anatomy of an 8-bit machine — 6502, Z80, 8086

One picture first.

        ┌──────────────────────────────────────────┐
        │            6502 CPU (NES, 1.79 MHz)      │
        │                                          │
        │   A (8b)   X (8b)   Y (8b)               │
        │   PC (16b) SP (8b, 0x0100-0x01FF)        │
        │   P (8b: NV-BDIZC flags)                 │
        └────────────┬─────────────────────────────┘
                     │  16-bit address bus -> 64KB
        ┌────────────┴─────────────────────────────┐
        │ 0x0000-0x07FF : 2KB internal RAM         │
        │ 0x0800-0x1FFF : RAM mirrors              │
        │ 0x2000-0x2007 : PPU registers            │
        │ 0x2008-0x3FFF : PPU mirrors              │
        │ 0x4000-0x4017 : APU & I/O                │
        │ 0x4020-0x5FFF : cartridge expansion      │
        │ 0x6000-0x7FFF : cartridge SRAM (opt.)    │
        │ 0x8000-0xFFFF : 32KB cartridge PRG-ROM   │
        └──────────────────────────────────────────┘

That single memory map is the entire NES. There is no deeper abstraction and no shallower one. Plug in a cartridge and the game code is mapped starting at 0x8000.

6502 — the master of simplicity

The 6502 is an 8-bit CPU but its simplicity is almost poetic.

  • Three registers. Accumulator (A), index X, index Y. That is it.
  • 256 bytes of stack. Hard-wired at 0x0100 through 0x01FF.
  • 56 instructions. You can learn them in a day.
  • 13 addressing modes. zero-page, indirect-indexed, indexed-indirect — these words will live in your head forever.

The smallest 6502 program. It fills the NES screen with blue.

; init.s - 6502 assembly for the NES
; The smallest program that paints the screen blue.

.segment "HEADER"
  .byte "NES", $1A      ; iNES magic
  .byte 2               ; PRG ROM 2 * 16KB = 32KB
  .byte 1               ; CHR ROM 1 * 8KB
  .byte $01, $00        ; mapper 0, vertical mirroring
  .byte 0, 0, 0, 0      ; padding
  .byte 0, 0, 0, 0, 0

.segment "STARTUP"
reset:
  sei                   ; disable IRQs
  cld                   ; clear decimal mode
  ldx #$ff
  txs                   ; stack pointer = $FF

  ; wait for PPU warm-up (twice)
  bit $2002
vblankwait1:
  bit $2002
  bpl vblankwait1
vblankwait2:
  bit $2002
  bpl vblankwait2

  ; background palette: $3F00 = universal background
  lda #$3f
  sta $2006
  lda #$00
  sta $2006             ; PPU address = $3F00
  lda #$01              ; color $01 = blue
  sta $2007             ; write to PPU

  ; turn the PPU on
  lda #%00001000        ; show background
  sta $2001

forever:
  jmp forever

.segment "VECTORS"
  .word 0               ; NMI
  .word reset           ; Reset
  .word 0               ; IRQ

You have probably never seen code like this if you spend your days writing React. But look — an entire game console is in those 30 lines. Writing directly to mapped memory addresses is how you talk to the PPU. No abstraction. The manual is the API.

Z80 — a warmer 8-bit

The Z80 is slightly more luxurious than the 6502. Game Boy, MSX, ZX Spectrum all use it.

  • More registers. A, B, C, D, E, H, L. Paired as BC, DE, HL.
  • Two index registers IX, IY.
  • A shadow register set. Swap context in one instruction (EXX) for interrupt handlers.
  • 700+ instructions. More to memorize than the 6502.

The Z80 leans toward "assembly should be writable by humans." The 6502 leans toward "give me the minimum." Which is better is a religious war, and doing both gives you respect for both sides.

8086 — the start of the IBM PC

The 8086 is 16-bit, but it carries the infamous segment register model.

  • Segment plus offset equals physical address. CS:IP, DS:SI, SS:SP, ES:DI.
  • Each segment is 64 KB. So you address 1 MB total with 16-bit registers.
  • MS-DOS INT 21h. All OS calls go through a single interrupt vector.

The 8086 is richer than the 6502 and more orderly than the Z80, but segments hurt the head. If you want to understand why modern x86-64 assembly looks the way it does, the 8086 is the shortest path.

Why this teaches well

The common thread across all three chips: the whole machine fits in your head.

  • You can memorize every register, every instruction, every memory region.
  • You know how many cycles each instruction takes. The instruction table fits on one page.
  • There are at most a handful of interrupts. The async model is fully visible.
  • You write code without a compiler. The assembler output is the bytes that end up in memory.

After this, you actually know what the machine does. Modern CPUs are more complex, but the principles are identical — registers, memory, interrupts. The intuition you build inside 64 KB transfers cleanly to 64 GB.


2. The modern retro toolchain — yes, you write ROMs in C

The era of writing only assembly for retro hardware is long over. The NES developer of 2026 writes in C. You still need to know assembly — you have to read compiler output. But 90% of daily work is C.

cc65 — the 6502 C compiler

cc65 is a C compiler plus assembler suite for the 6502 family. NES, Atari 2600/8-bit, Commodore 64, Apple II, Atari Lynx — one toolchain covers them all.

# Install cc65 (macOS)
brew install cc65

# Compile Hello World
cc65 -O -t nes hello.c
ca65 hello.s
ca65 -t nes crt0.s
ld65 -C nes.cfg -o hello.nes crt0.o hello.o nes.lib

# Run in an emulator
mesen hello.nes

Five commands and you have an NES ROM. That is 2026.

The C that cc65 produces is not modern C. Function calls are expensive (the stack is emulated in software), so you lean on globals, you inline aggressively. The compiler is not friendly — the optimizer is simple, and you frequently sprinkle inline assembly (e.g. an inline lda #$00).

And that is the point. You can see what C actually compiles to. Not the LLVM magic you cannot read — you can see line by line how one C statement turns into five assembly instructions.

CA65 — the assembler

If you write pure assembly, ca65 (bundled with cc65) is your tool. Powerful macros, segment definitions, conditional assembly, include files — it is genuinely modern.

; macros so subroutines feel like functions
.macro CALL routine
  jsr routine
.endmacro

; conditional assembly (different code for different mappers)
.if MAPPER = 1
  ; MMC1
.elseif MAPPER = 4
  ; MMC3
.endif

GBDK — Game Boy C compiler

The Game Boy uses a Z80 cousin (Sharp LR35902). GBDK is the C toolchain on top.

brew install gbdk
lcc -Wa-l -Wl-m -Wl-j -o hello.gb hello.c
# hello.gb is a real Game Boy ROM

GBDK ships with helpers for sprites, tiles, sound, and input, making the on-ramp easier than cc65. Putting a tile on the Game Boy LCD is one line.

// hello_gb.c
#include <gb/gb.h>
#include <stdio.h>

void main() {
    printf("Hello, Game Boy!\n");
    while (1) {
        wait_vbl_done();   // wait for VBlank = one frame
    }
}

This actually runs on a Game Boy. The ROM you just compiled on a 16-bit PC executes on 1989 hardware.

SDCC and z88dk — generic Z80

SDCC (Small Device C Compiler) is a C compiler for Z80, MCS-51, HC08, and so on. z88dk is a broader Z80 toolchain for ZX Spectrum, MSX, CP/M, and other Z80 systems.

Assembly vs C — when to use which

TaskAssemblyC
Game logicPossible but painfulRight tool
NMI handlerAlmost always assemblyInline asm
Cycle-precise IRQ splitAssembly onlyNot possible
Data tablesAssembly macrosArrays
Sound engineUsually assemblyDoable

The rule is simple — timing-critical code goes in assembly, everything else in C. When you start, do a little of both and settle into whichever your brain prefers.


3. The debuggers — time travel and memory views are back

This is the part that hits the hardest. Everything modern debugging lost is alive and well in retro debuggers.

Mesen — the gold standard for NES

Mesen is a precision multi-platform emulator (NES, Famicom, Game Boy, SNES, PC Engine) and its debugger is dominant.

What Mesen offers:

  • Rewind / time-travel debugger. Scroll back through the last few minutes of execution, cycle by cycle, in both directions.
  • Memory viewer. RAM, PRG-ROM, CHR-ROM, OAM, palettes, nametables — all in live panels.
  • Event viewer. A single grid shows every PPU and CPU event during a single frame, so you can see which instruction runs on which scanline at pixel precision.
  • Trace logger. Every executed instruction logged in disassembly.
  • CDL (Code/Data Log). Automatically labels which bytes in ROM are code and which are data.
  • Lua scripting. Inject custom hooks in the debugger. "Display this variable on screen whenever it changes" is five lines.

The fact that this tool is stronger than Chrome DevTools in 2026 in some real sense is exactly the lesson — modern dev tooling lost things that did not need to be lost.

bgb — the king of Game Boy debugging

bgb is the standard Game Boy debugger. Best on Windows, but runs under Wine on macOS/Linux (or use SameBoy as the cross-platform sibling).

  • Memory, registers, stack, I/O viewers
  • Breakpoints (address and conditional)
  • Sprite viewer, tile viewer
  • Disassembly

bsnes-plus — SNES precision debugger

bsnes-plus is a fork of byuu's bsnes SNES emulator with a debugger bolted on. Memory, trace, breakpoints — the full kit.

FCEUX — the NES classic

FCEUX is the oldest NES debugger still actively maintained. It was the standard before Mesen arrived. It is still light and fast, and the NES movie format (fm2) and the TAS (Tool-Assisted Speedrun) community remain centered on it.

SameBoy — native Game Boy debugger for macOS/Linux

If bgb is Windows-first, SameBoy runs natively on macOS and Linux. Its debugger is as good as Mesen's, and its accuracy is top-tier.

What we lost

Things modern debuggers cannot do — but retro debuggers do every day.

  • Time travel is the default. Chrome DevTools still calls "Time Travel" a beta; Mesen has rewound cycle-by-cycle for ten years.
  • Hardware-event visualization. Which scanline did this IRQ fire on? How many times was this memory region touched in one frame? One grid answers both.
  • Every state is visible. 64 KB fits on one screen. You will never look at a Pod's 16 GB heap and see it.

After spending a weekend in a retro debugger, "oh, a debugger can do that?" becomes engraved in your head. The limits of modern debuggers suddenly look like choices, not laws.


4. Fantasy consoles — PICO-8, TIC-80, LIKO-12

Here is where the renaissance happens.

A fantasy console is a development environment that mimics "an 8-bit/16-bit console that never actually existed." It is not a real 6502, but it honors the spirit — small screen, limited palette, limited memory, simple API.

PICO-8 — the start of it all

Lexaloffle's PICO-8 is the origin of this movement. The spec:

  • Display: 128 by 128, 16 fixed colors
  • Code: Lua, 8192 tokens (not lines — tokens)
  • Sprites: 128, 8 by 8 pixels each
  • Map: 128 by 32 tiles
  • Sound: 64 SFX, 64 patterns, 4 channels
  • Controller: 6 buttons (up/down/left/right, O, X)
  • Cartridge: 32 KB, share to a friend and they can edit immediately

The constraints are the entire point. A PICO-8 cartridge is the size that one person can finish in a week. That is the intended design.

PICO-8's Lua is a subset of standard Lua plus a game-focused API.

-- pico-8 cart: hello.p8 -- the smallest game
-- a dot you can move with the arrow keys

x=64 y=64

function _update()
 if btn(0) then x-=1 end
 if btn(1) then x+=1 end
 if btn(2) then y-=1 end
 if btn(3) then y+=1 end
end

function _draw()
 cls()
 pset(x,y,11)
 print("pico-8!",40,60,7)
end

Fifteen lines. Fifteen lines hold the core structure of a game. Input, update, render. Every game engine reduces to those three steps in the end. PICO-8 teaches that.

The PICO-8 console itself ships with a BBS (splore) so you can search and download cartridges directly. Dozens of new ones land every week. Anyone can read the source the instant they download — the cartridge IS the source.

TIC-80 — the open-source alternative

TIC-80 is the open-source cousin of PICO-8.

  • Display: 240 by 136, 16 colors (editable palette)
  • Code: Lua, Moonscript, JS, Wren, Fennel, Squirrel, Python — seven languages
  • Sprites: 256
  • Sound: 4 channels
  • Free, open source, runs in a browser

If the PICO-8 price tag (around USD 15) is a barrier, TIC-80 is the answer. Slightly more generous specs than PICO-8 and a much wider language menu. Smaller community than PICO-8 but very active.

LIKO-12 — a friendlier fantasy console on top of LOVE

LIKO-12 is another fantasy console that runs on LOVE2D. Similar design philosophy to PICO-8 but with larger cartridges and gentler limits. Great for learning.

Others — Pixel Vision 8, Pyxel, GB Studio

  • Pixel Vision 8 — C# based, cartridge-oriented
  • Pyxel — Python-based fantasy console. Comfortable for ML engineers
  • GB Studio — builds real Game Boy ROMs from a visual node editor. No code needed, real ROM out

Why "fantasy" consoles

The name is strange. Why imitate a console that never existed?

Two reasons.

  1. Constraints breed creativity. PICO-8's 8192-token limit, 128 by 128 display, and 16-color palette feel arbitrary, but they push you toward small finishable pieces. Indies who start AAA games finish 1% of them. People who start PICO-8 carts finish one per week.
  2. Nostalgia without legal mud. Real NES or Game Boy dev is possible, but Nintendo's IP and abandoned SDKs sit in a legal gray zone. Fantasy consoles are yours from day one — no Nintendo, no problem.

Fantasy consoles are the 8-bit spirit revived in 2026. Small indie scenes in Korea, Japan, the US, and Eastern Europe gather around them.


5. The communities — alive after 50 years

Retro computing does not work without people. Luckily, there are many.

NESDev Wiki — the NES bible

The wiki at nesdev.org is one of the best-organized hardware documents on the entire internet. Every mapper, every PPU bit, every APU channel is documented to cycle precision. It is the result of 30 years of people building new games piling on knowledge.

Sister resources:

  • NESDev BBS — live Q and A
  • NESDev Discord — active chat, new carts shared every week
  • wiki.nesdev.org/w/index.php/Programming_guide — beginner-friendly entry

AtariAge — the Atari mecca

A huge forum covering Atari 2600, 5200, 7800, 8-bit computers, Lynx, Jaguar — every model. Dozens of brand-new official cartridges ship each year. Yes, in 2026, new Atari 2600 carts ship. That is AtariAge.

GBADev / Game Boy Dev — Game Boy and GBA

gbadev.org (Game Boy Advance) and gbdev.io (Game Boy classic plus Color) are the hubs for Game Boy developers. GBDK, rgbds, tutorials, manuals, demos, and new games all collect here.

6502.org — 6502 across machines

Beyond the NES, this site covers Commodore 64, Apple II, Atari 8-bit, BBC Micro — the whole 6502 family. 30 years of assembly tutorials are piled up here.

Pouet — the demoscene treasure house

pouet.net is the central database of the demoscene. The demoscene is a computer-art movement born in 1980s Europe — short programs (demo, intro, tracker) that combine music, graphics, and code on constrained hardware, judged in competitions.

  • 64K intros — fit 3D graphics, music, and effects all inside 64 KB
  • 4K intros — 4 KB. 0.004 megabytes. A full audiovisual piece in that
  • 256-byte intros — 256 bytes. A ROM the size of a 1980s tweet, and the screen moves

The demoscene is the highest level of digital craft. Revision, Assembly, and Demosplash demoparties still run every year. 64K-intro competitions still happen in 2026. This is craft people did not let die.

Demozoo, Scene.org

demozoo.org and scene.org are archives of demos and intros. 30 years of demos to download and run on your own PC. A time capsule.

r/EmulationDev, r/PICO8, r/GameBoyDevelopment

Reddit's smaller subs are also active. The PICO-8 subreddit runs weekly cart sharing and code reviews.


6. A weekend project — the 12-hour "your first 6502 ROM"

Enough theory. Let us build one.

Saturday morning — set up the environment (1 hour)

# macOS
brew install cc65 mesen

# or on Linux
sudo apt install cc65
# Mesen needs .NET 6; grab a release from github.com/SourMesen/Mesen2

Saturday morning — Hello World ROM (2 hours)

Clone bbbradsmith/NES-ca65-example from GitHub. It is the standard starting point for cc65-based NES dev.

git clone https://github.com/bbbradsmith/NES-ca65-example
cd NES-ca65-example
make
mesen example.nes

"Hello World" comes up on the screen. Your first NES program. Open the Makefile and follow the build. Open the .s files and read the assembly. Open Mesen's debugger. Single-step with F10.

Saturday afternoon — controller input (3 hours)

The NES controller is an 8-bit shift register. Write 1 to $4016 to latch the input, then write 0 to start shifting. Read $4016 eight times in a row to get A, B, Select, Start, Up, Down, Left, Right.

read_controller:
  lda #$01
  sta $4016         ; start latch
  lda #$00
  sta $4016         ; start shift
  ldx #8
  loop:
    lda $4016       ; one bit at a time
    lsr             ; bit -> carry
    rol controller  ; carry -> controller
    dex
    bne loop
  rts

Each bit of the controller variable is one button. Those eight lines are the entire NES input system. If you are used to addEventListener("keydown", ...), this is striking — no interrupts, polling only, read eight times, done.

Saturday evening — move a sprite (4 hours)

The NES OAM (Object Attribute Memory) is 64 sprite slots. Each sprite is 4 bytes (Y, tile, attribute, X). Once per frame, write to OAM via $2003 and $2004 (or DMA an entire page via $4014).

In PICO-8 a sprite is one line: spr(0, x, y). On the NES it is a 12-line OAM update routine. That difference is the lesson.

Sunday morning — sound (2 hours)

The NES APU has 5 channels — two pulses ($4000-$4007), a triangle ($4008-$400B), noise ($400C-$400F), and DMC ($4010-$4013). Write directly to the channel registers and the chip plays.

; pulse 1 channel: play A4 (440Hz)
lda #%10111111   ; duty 50%, length forever, volume 15
sta $4000
lda #%00001000   ; sweep off
sta $4001
lda #$fd         ; period low byte
sta $4002
lda #$00         ; period high byte
sta $4003

Four register writes and the NES sings. This is what direct synth-chip control feels like, without a sound-card abstraction in the way.

What you have after 12 hours

If Saturday and Sunday went well, by the end you will have:

  • A "Hello World" ROM
  • A ROM where a sprite moves with the controller
  • The skeleton of a tiny game with collision and a score
  • A simple BGM loop
  • And a mental model of how the whole thing runs

That mental model is the prize. Once you have written one frame at 60 Hz inside 64 KB, your debugging is different forever after.


7. The grown-up excuse — does this help the day job?

The question we always get: "OK but does this help your real work?" The answer is in two parts.

Yes, actually

  • Memory alignment and cache lines. On the 6502, zero-page (0x0000-0x00FF) is faster than the rest. One cycle. Modern CPUs work the same way. L1, L2, L3, main memory. The same intuition carries over.
  • Interrupt latency. "The NMI must finish before the next frame" is structurally the same question as "what happens when the queue fills up?" in a modern distributed system.
  • Instruction cycle counting. You naturally start thinking "how many cycles does this function take?" CPU-bound analysis becomes intuition.
  • The essence of DMA. The NES OAM DMA moves one page to the PPU once per frame. Seeing that makes PCIe DMA, GPU texture uploads, and NVMe queue behavior fall into place in one line.
  • A world without error codes. A subroutine returns success or failure via the carry flag. Once you have done it that way, you understand why Result and Option types had to be invented.

And it is fine if it does not

Honestly — it is fine if it does not help. Not every hobby has to feed the day job. A guitarist playing classical guitar does not make their electric playing better. It is still worth doing.

The real value of retro computing is the joy. Small screen, big constraints, weekly finishable projects, a community alive after 50 years, time-travel debuggers, total control over every byte. That kind of joy is what got lost in the SaaS era.

The React code you wrote this week has a non-trivial chance of being gone in six months. The PICO-8 cart you make tonight will run identically in 30 years. That gap is what craft is.


Epilogue — the soul inside an 8 KB ROM

If this whole essay has to compress to one line, it is this.

"You can build a universe inside 64 KB. And the universe still runs 30 years later."

Starter checklist

If you want to begin this weekend:

  • brew install cc65 mesen (or your OS equivalent)
  • Install PICO-8 or TIC-80 (TIC-80 is free)
  • Clone bbbradsmith/NES-ca65-example, run make
  • Open the ROM in Mesen, F10 to single-step
  • Read the NESDev wiki for 30 minutes
  • Watch one 64K intro on Pouet
  • Ship your first cartridge to the PICO-8 BBS (or itch.io)

Anti-patterns

  • Do not start a AAA game. Start at a size you can finish in a week. The first cart should be at the level of "ball bounces around the screen."
  • Do not try to memorize the assembly first. Learn instructions as you need them. Keep the instruction table next to the keyboard.
  • Do not stay only in emulators. Once, put a ROM you wrote on real hardware. A flash cartridge like EverDrive lets you run your own ROM on a real NES.
  • Do not work alone. NESDev Discord, PICO-8 BBS, AtariAge — join where people are.
  • Do not let an unfinished cart drag for too long. Better to ship a 50% cart in a week than to polish a 80% cart for a year.

What is next

The next post is "Finish a PICO-8 game in 7 days — the poetry of 8192 tokens" (working title), which dives into PICO-8 from chapter 4. Token-saving tricks, designing from zero, shipping to the BBS — all on a weekly cadence.

The post after that is "The demoscene, the universe inside 64 KB — how an intro is made" (working title), covering the history and present of the demoscene plus a guide to writing your first 256-byte intro.

"When abstractions pile too high, you have to drop to the floor once in a while. That is the only way to see what was piled on top."

— a weekend back at retro computing, fin.


References

현재 단락 (1/324)

You probably spent today debugging a React Server Component, tracing which code ran in which runtime...

작성 글자: 0원문 글자: 21,530작성 단락: 0/324