1. Overview

The 32-game launcher on the host viewer.
This project is a multi-system retro console on a Terasic DE0-Nano. It runs software from three periods on one board: DOOM (1993), CP/M 2.2 and Microsoft BASIC-80 (late 1970s and 1980s), and Chip-8 (1977). All three runtimes sit behind one bare-metal launcher, on a RISC-V core written for this project. Nothing runs on top of an operating system.
The work divides into four parts: the CPU, the FPGA machine built around it, the test harness used to develop both, and the console software. The sections below follow that order.

Terasic DE0-Nano, front. Cyclone IV E EP4CE22F17C6N, 32 MB SDRAM, 50 MHz oscillator, USB-Blaster for JTAG.
2. At a glance
| Item | Value |
|---|---|
| Board | Terasic DE0-Nano, Altera Cyclone IV E EP4CE22F17C6N |
| CPU | Custom dual-issue in-order RV32IM at 50 MHz, CPI 0.727 measured on DOOM |
| System memory | 32 MB SDRAM, 16-bit bus |
| Memory layout | 158.6 KB firmware, 12 MB heap, 512 KB stack, 5.11 MB asset blob |
| Device utilization | 17,743 logic elements (79 percent), 6,984 flip-flops, 54 M9K, 12 DSP |
| Game catalog | 32 titles: 7 native and 3D, 6 CP/M 2.2, 19 Chip-8 |
| Primary display | 64x32 RGB332 framebuffer at 45 FPS over 921,600 baud UART |
| Hardware display | 0.96 inch I2C OLED, 128x64, 32.6 FPS, hardware 2x2 scaler |
| Input | Host keyboard over UART with press and release events, decoded in RTL |
| Load | 5.27 MB image over serial in about 57 seconds, CRC32 verified |
| Timing | Slow corner worst slack -3.998 ns; nominal silicon runs on the bench |
3. The bandwidth problem and the 64x32 decision
DOOM renders to a native Mode 13h buffer of 320x200, which is 64,000 bytes. Frame logic completes in about 28 ms (roughly 35.7 FPS internally), but the serial link is the ceiling. At 921,600 baud the theoretical maximum is 92.16 KB/s, and a 64,000-byte frame takes 694 ms on the wire. The game logic ran at full speed while the display ran at 1.44 FPS.
The intermediate step was 160x100: 16,000 bytes per frame, 174 ms, about 5.75 FPS. Playable, but still behind human reflex speed.
The console settled on a uniform 64x32 framebuffer, 2,048 bytes per frame, which crosses the wire in 22.2 ms and gives a steady 45 FPS. The choice also holds up on other axes: 64x32 is the native resolution of the 1977 Chip-8 virtual machine, it maps cleanly to fixed-point raycasting columns, and it scales 2x2 to a 128x64 monochrome OLED with no geometric distortion.
Resolution vs wire time at 921,600 baud (92.16 KB/s):
320x200 (64,000 bytes): 694 ms per frame -> 1.44 FPS
160x100 (16,000 bytes): 174 ms per frame -> 5.75 FPS
64x32 (2,048 bytes): 22 ms per frame -> 45.00 FPS
In the memory map the framebuffer occupies a fixed 2 KB window at 0xFFF00000 to 0xFFF007FF. Each byte is an 8-bit RGB332 pixel for serial streaming. The OLED controller interprets any non-zero byte as a lit pixel, so the same buffer drives both displays without conversion.
Code, from games/common/console.h:
#define FB_W 64
#define FB_H 32
#define FB ((volatile uint8_t *)0xFFF00000u)
#define MMIO_BASE 0xFFFFF000u
#define MM_KEY (*(volatile uint32_t *)(MMIO_BASE + 0x014u))
#define MM_DUMP (*(volatile uint32_t *)(MMIO_BASE + 0x028u))
void dump_tiny(void) {
MM_DUMP = 2u; /* Trigger 64x32 tiny mode dump in mem_top_fpga */
}
4. Frame commit path: 154 microseconds of CPU time per frame
When a frame is ready, the game writes 2 to MM_DUMP (0xFFFFF028). This replaces the earlier multi-byte host command protocol (0xFC, 0xFD, 0xFE) with a single MMIO write.
In mem_top_fpga.v, that write makes the SDRAM arbiter read 512 words (2,048 bytes) from the framebuffer backing store at FB_SDR_WORD (0x7FC000). Reading 512 words takes about 7,680 system clock cycles, about 153.6 microseconds at 50 MHz. The FPGA has a 4,096-byte TX FIFO, so the whole frame fits in one burst. As soon as the last word lands in the FIFO, the arbiter releases the gated core clock and the CPU continues.
The CPU is stalled for about 154 microseconds per frame. The autonomous UART feeder drains...
Read more »
M_Jagadeesh97



Scott Boudreaux
Mars
SHAOS
Jara