RP6502-FPGA

RP6502 - Field Programmable Gate Array

Introduction

The whole machine, in fabric. The 65C02, the 65C22, and the entire RP6502-VGA video system are RTL, and the RIA’s operating system runs on a Hazard3 RISC-V soft CPU executing a trimmed build of the same firmware C the real machine runs. That isn’t a reimplementation of the Picocomputer — it’s the Picocomputer, with the same split between a 6502 and something modern minding the store.

Which means the Picocomputer 6502 is now entirely ours. Nothing in the machine depends on a part only WDC makes, or a part only Raspberry Pi makes. The 6502 is source. The VIA is source. The operating system runs on a soft CPU anyone can put in any fabric. The design can be produced whole from the repository, and nobody is in a position to end it.

The Analogue Pocket Core

Everything the machine does, on a handheld. Every video mode, the PSG and the OPL2, the dock, the keyboard layouts, the mouse, sleep, memories, and the microSD card as MSC0:.

Install

Copy Cores, Platforms, Saves, and Assets onto the microSD card in the same folder structure. They merge with what’s already there and nothing replaces another core’s files. Then open the core from the Pocket menu under openFPGA.

ROMs

Put .rp6502 files in Assets/rp6502/common/ and the core asks you to pick one when it opens. Find them on Discord, which has a forum for ROMs, or on itch.io under the RP6502 tag:

Saves

Saves/rp6502/common/ is the core’s working directory, so a program’s plain open("game.save", ...) lands in the same place here as it does everywhere else. An absolute name travels untouched, which is how you reach the package’s own folder — MSC0:/Assets/rp6502/common/ is writable too.

There is no delete, rename, or mkdir. The Pocket doesn’t offer them.

Core Settings

Four entries, and the reasons are worth knowing.

Keyboard picks the layout. There’s one entry rather than a list plus an alternate, because on real hardware reaching the monitor to change layouts interrupts whatever you were doing, and this menu is two button presses away.

UTC offset is three entries — a side, an hour, and a quarter hour. The Pocket knows nothing about time zones, so the offset has to be set by hand, and a list holds at most sixteen options against an offset that spans twenty-seven hours.

Sleep

The Power Button sleeps the Pocket and wakes it again. Sleeping produces a savestate, and the 6502 resumes on the exact cycle it froze. Two things don’t survive, both on purpose:

  • The audio engines’ internal state. The registers come back and a held note is re-keyed, but what the engines had made of them starts again — you may hear a click.

  • Up to sixteen console bytes that hadn’t been read yet. Reading them to save them would pop the queue, which would eat a character every time you made a savestate.

Caution

Sleeping while a program is reading or writing a file can lose the program — the operation comes back EIO. This is a bug rather than a limit, tracked at issue #183.

The Dock

The Pocket hands the core four controller slots, and the core hands all four straight to the firmware as HID reports — buttons and axes, exactly what the Picocomputer expects. So the keyboard, the mouse, and up to four controllers all work through the same drivers the real hardware uses: international layouts, dead keys, key repeat, the escape sequences a terminal expects, and four players in slot order.

Internals

┌─ the Pocket ─ APF shell, core_bridge_cmd ─── clk_74a 74.25 MHz ─────┐
│ data slots · savestate · RTC · four controller slots · the scaler · │
│ the I2S codec · the pad ring. Analogue's, and unchanged.            │
└──┬───────────────────────────────────────────────────────────┬──────┘
   │ bridge writes, target commands, controller state          │
   │                                     picture, sound, log   │
┌──┴───────────────────────────────────────────────────────────┴──────┐
│ src/host/pocket — the wrapper                     clk_sys 50.4 MHz  │
│ pocket_bridge  pocket_file  pocket_sst   pocket_video  pocket_i2s   │
│ pocket_sdram   pocket_sram  pocket_dbg   pocket_dbglog  pocket_fifo │
│ pocket_bars    pocket_pll: clk_sys ──> altclkctrl ──> clk_mach      │
│                                                                     │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ src/rtl — the machine, platform independent                     │ │
│ │                                                                 │ │
│ │  ┌────────┐       ┌────────┐   the VIA at $FFD0-$FFDF and the   │ │
│ │  │ w65c02 ├───────┤ w65c22 │   RIA window at $FFE0-$FFFF, where │ │
│ │  └───┬────┘       └────────┘   they sit on a real board         │ │
│ │      │                                                          │ │
│ │  ┌───┴────┐   phi2_div makes PHI2 a clock enable on clk_mach,   │ │
│ │  │ria_regs│   not a clock of its own — 0.1 to 8.0 MHz, exact    │ │
│ │  └───┬────┘                                                     │ │
│ │      │                                                          │ │
│ │  ┌───┴─────────────────────────────────┐  clk_rv 25.2 MHz —     │ │
│ │  │ rv_soc — Hazard3 RISC-V, 96 KB TCM  │  half clk_sys, off the │ │
│ │  │ a trimmed build of src/ria firmware │  PLL, rising with it   │ │
│ │  └───┬─────────────────────────────────┘                        │ │
│ │      │ one system bus, one master                               │ │
│ │  xram64k   vid_timing  vid_prog  vid_sched  vid_fill  vid_mode  │ │
│ │  vid_mode0 vid_mode1 vid_mode2 vid_mode3 vid_mode4 vid_mode5    │ │
│ │  vid_pixtail  vid_sprite  vid_sbuf  vid_palcache  vid_palram    │ │
│ │  vid_font  vid_compose   aud_psg  aud_opl  aud_rsmp             │ │
│ │  sst_engine, the serializer, on clk_sys, never gated            │ │
│ └────┬────────────────────────────────┬───────────────────────────┘ │
│      │ stage port,                    │ ram_a is the 6502's port,   │
│      │ through pocket_sdram           │ ram_b the soft CPU's window,│
│      │                                │ both through pocket_sram    │
└──────┼────────────────────────────────┼─────────────────────────────┘
       │                                │
┌──────┴───────┐                 ┌──────┴──────────┐
│ 64 MB SDRAM  │                 │ 256 KB SRAM     │  asynchronous,
│ staging store│                 │ the 6502's 64 KB│  55 ns every time
│ ROM, fonts,  │                 └─────────────────┘
│ code pages,  │                 the board's third chip, 16 MB of
│ layouts      │                 PSRAM, is tied off and unused
└──────────────┘

Read the boxes as nesting, not stacking. The top level is Analogue’s template with our clocks and one instance of the wrapper in it; the wrapper holds one instance of the machine; and the machine knows nothing about either. Everything the Pocket can say arrives over the APF bridge on its own clock and is crossed once before the machine sees it.

The triangle in the middle is the real machine’s split, in gates. The 6502 reaches the VIA at $FFD0 and the RIA’s register window at $FFE0 exactly as it does on a board, and behind that window sits a Hazard3 RISC-V running the same firmware C an RP2350 runs, doing the same job: syscalls, HID, and ROM loading.

Two clocks and two chips finish the picture. The soft CPU runs at half speed because its frontend is the one block that can’t make 50.4 MHz. The 6502’s 64 KB lives in the board’s asynchronous SRAM. The SDRAM is the staging store the Pocket writes ROMs, fonts, code pages, and keyboard layouts into.

All of it is checked against the emulator. The machine is simulated with Verilator and run on the same ROMs as emu_core, the same code the RP6502-EMU is built from, and the two are compared.

MiSTer

Planned.