Home›Industry News›M9B: A RISC-V computer in a Tang Nano 9K FPGA that runs Doom and Descent
← Back to Industry News
Open Source

M9B: A RISC-V computer in a Tang Nano 9K FPGA that runs Doom and Descent

Hacker News ·
This is the original English full text (~5092 words), with the original images mirrored on this site; for details please refer to the source page.

m9b: a RISC-V computer on the Tang Nano 9K

m9b is a small computer built in the FPGA of Sipeed's Tang Nano 9K (a Gowin GW1NR-9): a VexiiRiscv CPU at 36 MHz with caches, the board's 8 MB of on-package PSRAM, 720×480 HDMI video and 48 kHz audio, two USB ports for keyboards and mice, and the SD card slot. It boots into a screen that lists the programs on the SD card, and it runs five DOS-era games, ported to it (Ultima VII on two engines):

All have sound effects and music; Ultima VII's (both engines) come from Exult's Roland MT-32 recordings (without them, it has The Black Gate's AdLib music and no sound effects). The music is rendered or converted on the PC ahead of time and streamed from the card.

This repository ties the parts together: each is a repository of its own, included here as a git submodule, so clone with --recursive (or run git submodule update --init afterwards; make does that too).

Each README has the same layout: what the part is and its status, a Sources table (the upstream projects it is built from or uses, with the versions), how to build it, how it works, and Changes to ... : what was changed in the upstream code (marked M9B there). The SoC's parts from elsewhere (VexiiRiscv, the HDMI and USB host cores, FatFs) are in core/README.md , Sources.

No game data is in any of them. Each game's data/README.md says which version of the game is needed and what goes there; sdcard/README.md has the overview.

A Tang Nano 9K , an HDMI display, and a microSD card (1 GB or more). USB keyboard and mouse: two USB-A sockets wired to header J5, with 15 kΩ pull-downs on D+ and D− ( core/README.md , USB host). The serial console also works as a keyboard for the menus. Optionally a 3.3 V USB-serial adapter on J5, for fast program uploads ( core/README.md , Serial loader). The board's own USB serial port works too, more slowly. Software, on Debian or Ubuntu:

sudo apt install make git gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf \ libstdc++-riscv64-unknown-elf-picolibc python3 openfpgaloader \ curl unzip 7zip cmake g++ ffmpeg mtools dosfstools fdisk (The second line is for the SD card: downloads, music rendering and the disk image. 7zip is p7zip-full on older releases.)

The FPGA bitstream is built with the Gowin IDE : Gowin EDA V1.9.11.03 Education, a free download from Gowin. Set GOWIN_HOME to the directory that holds its bin/gw_sh (default ~/gowin/IDE ). The SD card needs a few more tools (see sdcard/README.md ). The simulations need Icarus Verilog, and the System Shock and Ultima VII host test harnesses need gcc-multilib g++-multilib .

From scratch to a working card

git clone --recursive https://github.com/the-parts-bin/m9b-system.git cd m9b-system Put the game data in place: each game's data/README.md says what goes there (symbolic links work). Descent and Tyrian need nothing: they are downloaded. For example:

cp ~/Downloads/doom19s.zip doom/data/ ln -s ~/.local/share/Steam/steamapps/common/SS1/SSHOCK sshock/data/SSHOCK ln -s path/to/ULTIMA7 exult/data/ULTIMA7 # The Black Gate ln -s path/to/SERPENT exult/data/SERPENT # Serpent Isle ln -s path/to/exult-audio exult/data/exult-audio # Exult's MT-32 packs (optional) Then

make sdcard builds the ports, collects the data, renders the music, and writes sdcard/out/m9b-sd.img (and the card's files in sdcard/out/card/ ). It checks for the tools it needs first, and leaves out a game whose data isn't there. Write the image to the card ( dd replaces everything on it: check the device name with lsblk ):

sudo dd if=sdcard/out/m9b-sd.img of=/dev/sdX bs=4M conv=fsync status=progress The board needs the bitstream and the firmware in its flash once:

make bitstream # the FPGA bitstream (Gowin IDE) make flash # bitstream + firmware into the board's flash (openFPGALoader) Insert the card and power the board on: the boot screen runs its self-tests and lists the programs. Pick one with the arrow keys and Enter.

make # firmware, the five game ports, the board tools (u7/: make sdcard) make bitstream # the FPGA bitstream (Gowin IDE) make flash # bitstream + firmware into the board's flash (openFPGALoader) make sdcard # the SD card (sdcard/README.md; SDCARD="--doom ..." for data elsewhere) During development, core/tools/run.py PROGRAM.bin uploads a program over the serial port and runs it without touching the card, and make sync brings the card in the board up to date with sdcard/out/card/ through the serial port, sending only what changed ( core/tools/sdput/sdput.py ). core/README.md covers both. Each game's README covers its build options, how it was made to fit, and its changes to the upstream code.

The bitstream is close to full (about 88% of the logic, 25 of 26 block RAMs) with little timing margin: check the timing summary after a build ( core/README.md , Clocks).

Each repository has its own license; this one (the SD card scripts and the top-level files) is under the Apache License 2.0 ( LICENSE ).

The game ports keep their upstream licenses, which also cover the platform code added in each ( port/ , tools/ ). The game data isn't covered by any of these, and none of it is included.

Read Original →
Source: Hacker News