-
Notifications
You must be signed in to change notification settings - Fork 0
Home
📖 Documentation: the full guide lives in the Wiki (mirrors docs/). 🧩 Part of: the 6502 SBC emulator project (emulator Wiki). This repo is linked there as the
fpga/submodule.
This repository contains the hardware implementation track for the 6502 SBC emulator. The goal is to rebuild the emulator's machine as synthesizable VHDL for real FPGA targets while keeping the memory map and software-facing behavior compatible.
The FPGA build reuses ROMs and kernel sources from the parent emulator repository
(via ../roms/ and ../../tools/kernel/), so check it out as the fpga/
submodule inside 6502-sbc-emulator
when building.
The first milestone is a hardware skeleton:
- shared address/data bus types and constants
- fixed memory map decoder matching the C emulator
- FPGA top-level shell
- imported T65 6502-compatible VHDL CPU core plus local adapter
- synthesizable RAM/ROM building blocks
- a first synthesizable VIA 6522 MVP
- a first synthesizable UART 6551 MVP
- placeholder device blocks for disk MVP, VIC, and sound
- simulation entry points for incremental verification
The placeholders intentionally expose the intended bus contracts before each chip is fully implemented. This lets us add real behavior one component at a time without changing the top-level wiring repeatedly.
The checked-in Xilinx ISE project for the PIX16 board lives at:
fpga/boards/pix16/project/fpga.xise
It targets xc6slx16-ftg256-2. The current hardware bring-up target is
boards/pix16/rtl/pix16_sbc_sd_boot_top.vhd with boards/pix16/constraints/pix16_sd_boot.ucf.
This top integrates the T65 CPU, SDRAM-backed main RAM, 2 KB text VRAM, VIA,
UART, VGA, SD-card ROM loading, a boot status screen, an SDRAM self-test, and a
UART hardware monitor.
The older pix16_sbc_minimal_top flow remains useful as a small VGA/T65 smoke
test. The SD boot top is the active path for firmware work because it loads the
16 KB ROM window $C000-$FFFF into writable shadow RAM.
For fast iteration, press the monitor button and upload a ROM over UART without rewriting the SD card:
python fpga/tools/upload_monitor_hex.py --build-demo --port COM15 --run --verboseSee docs/UART_MONITOR.md for monitor commands, memory ranges, and ROM upload
details.
ISE build products are intentionally ignored by .gitignore; fpga.xise is the
project file that should be kept under version control.
The Gowin project for the Tang Primer 20K lives at:
fpga/boards/tang_primer_20k/project/tang_sbc.gprj
It targets the Sipeed Tang Primer 20K / Gowin GW2A-18. The current board top is
boards/tang_primer_20k/rtl/tang20k_sbc_top.vhd. It brings up HDMI (DVI-style
TMDS, 27 MHz pixel clock, CEA-861 480p timing for standard 640×480 @ 59.94 Hz),
displays the boot/status diagnostic screen first, initializes the on-board
microSD/SDIO slot in SPI mode, loads the 16 KB $C000-$FFFF ROM image into
shadow ROM, and releases the T65 CPU after a successful load.
Current verified bring-up:
- HDMI boot/status output works.
- CH340 UART works from the PC as the board serial port, tested as
COM12. - KEY1 enters the FPGA UART monitor and holds the 6502 CPU.
- PS/2 keyboard on PMOD 0 (
T7/T8) works — keystrokes are injected into the UART receive path so EhBASIC sees them as serial input. - Without a card in the on-board microSD slot, boot debug output correctly reports that SD initialization/read cannot complete.
The Tang path currently uses internal BSRAM for main RAM instead of the on-board
SDRAM. The CH340 UART runs at 230400 8N1; the USB-OTG connector is separate and
is not the SBC UART. The on-board microSD slot is used in SPI mode on
N10/N11/R14/M8 as documented in boards/tang_primer_20k/README.md.
USB HID keyboard input via the nand2mario usb_hid_host bit-bang core was
attempted but USB enumeration did not complete reliably (see
boards/tang_primer_20k/README.md for details). PS/2 was adopted instead.
Run from this directory:
make testThe current GHDL tests cover:
- address decoding for all mapped device windows
- reset-vector fetch from ROM at
$FFFC-$FFFD - ROM-scripted bus write into SRAM address space
- SRAM readback after write
- VIA 6522 register, port-mask, IER/IFR, and timer-IRQ behavior
- UART 6551 status, TX, RX, overrun, programmed reset, and RX IRQ behavior
- conversion of a real emulator ROM into VHDL hex and reset-vector readback
- T65 adapter analysis/elaboration and defined bus outputs after reset
- T65 system boot from a tiny real 6502 ROM that executes
LDA #$42; STA $0002 - T65 execution of a tiny real 6502 ROM that writes
$41to UART DATA at$8810 - T65 execution of a tiny real 6502 ROM that drives VIA Port B through DDRB/ORB
- T65 handling of a VIA Timer 1 IRQ and execution of an IRQ handler through
the
$FFFE-$FFFFvector - T65 boot smoke test with composed
kernel.rom + msbasic.rom, verifying reset fetch, VIA DDRA init, and kernel screen-pointer setup
The local third-party CPU import lives under third_party/t65/. It currently
contains the T65(b) VHDL core and a project-local adapter:
third_party/t65/rtl/ imported T65 source files
rtl/core/cpu/t65_adapter.vhd local 16-bit bus adapter
The adapter maps T65's 24-bit address bus down to the SBC's 16-bit address space,
exports write-enable/data signals, and feeds memory/peripheral read data directly
to T65's DI input for the documented 6502 instruction subset used so far.
For now, sbc_top.vhd still uses the script-driven cpu6502_slot so the existing
smoke tests remain deterministic. A second top-level, rtl/sbc_t65_top.vhd, swaps
in t65_adapter and is covered by a tiny real 6502 ROM boot test.
T65 currently uses the ROM and SRAM components' ASYNC_READ mode in
sbc_t65_top.vhd. The T65 system top advances the CPU every other system clock
and registers read data during the stable bus phase so FPGA-style synchronous
writes and asynchronous reads have deterministic simulation timing. The
script-driven smoke-test top keeps the default synchronous memory paths.
sim/tb/tb_sbc_t65_indirect_vic.vhd is kept as an experimental/quarantined test for
STA ($zp),Y into VIC text RAM. It currently exposes a T65 indirect-addressing
integration issue and is intentionally not part of the default make test target.
The VHDL ROM loader reads text files in offset byte format. Convert emulator ROM
artifacts with:
python tools/bin_to_vhdl_hex.py --size 0x4000 --output sim/generated/chess_rom.hex ../roms/chess.romMultiple ROM windows can be composed with file@offset:
python tools/bin_to_vhdl_hex.py --size 0x4000 --output sim/generated/sbc_rom.hex ../roms/kernel.rom@0x0000 ../roms/msbasic.rom@0x1000For the EhBASIC system image, keep the kernel at the same offset and replace only the BASIC window:
python tools/bin_to_vhdl_hex.py --size 0x4000 --output sim/generated/sbc_ehbasic_rom.hex ../roms/kernel.rom@0x0000 ../roms/ehbasic.rom@0x1000make test currently generates sim/generated/chess_rom.hex and
sim/generated/sbc_rom.hex automatically. make roms also generates
sim/generated/sbc_ehbasic_rom.hex. The generated SBC images compose
kernel.rom at offset $0000 and the selected BASIC ROM at offset $1000.
The PIX16 SD boot path keeps the FPGA bitstream stable and loads the 16 KB SBC ROM window from the SD card into shadow RAM at reset:
# from fpga/:
make sd-boot-image
# from fpga/boards/pix16/:
cd boards/pix16 && xtclsh scripts/create_sd_boot_ise_project.tclIf xtclsh is not in your normal shell PATH, run the project command from the
Xilinx ISE Command Prompt. The image file is
sim/generated/sbc_ehbasic_sd.img and contains kernel.rom + ehbasic.rom for
CPU addresses $C000-$FFFF.
The SD image is persistent across FPGA resets. The UART monitor upload is a development shortcut that writes the same shadow-ROM RAM after boot and is lost on reset/reprogramming.
$0000-$7FFF SRAM
$8000-$87FF VIC text/color RAM
$8800-$880F VIA 6522
$8810-$8813 UART 6551
$8820-$882F DISK MVP
$8830-$8839 SOUND Voice 0
$8840-$884F VIC blitter registers
$8850-$888F VIC sprite registers
$8890-$8899 SOUND Voice 1
$889A-$88A3 SOUND Voice 2
$88A4-$88AD SOUND Voice 3
$8900-$89FF VIC sprite pixel data
$9000-$900F VIC control registers
$9010-$AF4F VIC bitmap RAM
$C000-$FFFF ROM
- Bus, reset, clocking, SRAM/ROM, and a trivial ROM-driven smoke test.
- CPU core integration, ideally with Klaus Dormann functional-test compatibility.
- VIA 6522 enough for keyboard/IRQ behavior.
- UART 6551 transmit/receive with FPGA board UART pins.
- VIC text mode, then bitmap RAM, raster IRQs, sprites, and blitter.
- Sound voice register file, then waveform generation, ADSR, and mixer/PWM or I2S.
- Board-specific constraints and PLL/clock-domain work.
fpga/
boards/
pix16/ PIX16 Spartan-6 board (self-contained)
rtl/ board-specific top-level VHDL
constraints/ UCF pin constraints
scripts/ ISE build scripts
project/ ISE project file (fpga.xise)
bitstreams/ programming files (.mcs/.cfi)
tang_primer_20k/ Gowin GW2A-18 board (HDMI, CH340 UART, on-board SD boot path)
rtl/core/ board-agnostic synthesizable VHDL
cpu/ CPU adapters
mem/ RAM/ROM primitives
peripherals/ memory-mapped chips
boot/ boot subsystem modules
sim/
tb/ VHDL testbenches
hex/ static ROM hex files
sw/ 6502 firmware (assembly sources)
tools/ build utilities
third_party/ imported open-source cores
docs/ FPGA implementation notes
Generated from 6502-sbc-fpga Markdown documentation. Part of the 6502 SBC emulator project (emulator Wiki).