An 8080 Space Invaders emulator in Rust

Overview

Space Invade.rs

An 8080 Space Invaders emulator written in Rust

space-invaders-1

This is an 8080 emulator running the 1978 Space Invaders game by Taito, written in Rust. space-invade.rs is my third emulator (the first one was Chip-8 and then an Apple ][ emulator, both written in Kotlin). I chose Rust for this project to experiment with a different design and see how far I could push the performance.

Running the emulator

On Windows, you can just cargo run --release.

On macOS, you will need to install SDL2 first (brew install sdl2).

I haven't tested on Linux.

cargo test will run the cpudiag emulator test.

Playing it

  • Press C to insert a coin.
  • Press 1 or 2 to select the number of players.
  • Player 1: left and right arrows to move, space to shoot.
  • Player 2: a and d to move, s to shoot.
  • 'p' will pause the game, any key will resume.
  • ESC to close the window.

The 8080 processor

The 8080 turned out to be quite an advanced processor and even though it came out before the 6502 (1974 and 1975 respectively), I grew to appreciate its rich set of instructions (the 6502 only has 56, the 8080 has over 200) and how elegantly you can write some algorithms.

The emulator in this project is close to complete, including:

  • All the instructions
  • Correct cycle count
  • Implementation of binary coded decimal (DAA)
  • Interruptions (EI and SI and some RST but not all since Space Invaders only uses a few)

The emulator also passes the cpudiag diagnostic application, which you can run with cargo test.

Space Invaders

The arcade game had quite an interesting architecture, please see the resources section if you need in-depth details. In a nutshell:

  • The resolution is 224x256 with one bit of depth, so just black and white. The arcade used tranparent green and red tapes on top of the screen to simulate additional colors, which this emulator does as well.
  • The graphic memory starts at 0x2400 with each byte representing eight bits (note: the screen is flipped 90 degrees).
  • The video generates two interrupts: one when the beam is halfway through the screen and one at the end of the screen (VBL). Each of these interrupts calls a RST which tells the CPU to jump at $08 and $10 respectively. These two addresses are in charge of updating the half of the screen that the beam just finished drawing (quite a clever hack). My emulator doesn't go to that level of details and simply refreshes the graphic during the VBL.
  • While the 8080 knows how to shift bits, it only has instructions to shift by one bit, and these are pretty slow, which makes shifting variable numbers of bits costly. This is unfortunate since it's the only way that this hardware can animate its graphics, so the designers created a multiple bit shifter outside in the game hardware itself and hooked it up with its input and output instructions. Refer to the detailed architecture (or the code) to understand how this works, but I thought this was another very clever design around hardware limitations of the time.

The main logic is in the file sdl2.rs, which spawns the emulator in a separate thread. That thread updates the graphic memory which the SDL 2 main loop uses to draw the graphics on the main screen.

The emulator is calibrated to run at 2Mhz with the following logic, which you will find in run_one_frame() in emulator.rs:

  • Run as many cycles as necessary to reach the first half of the screen (about 16,500)
  • Generate the first interrupt
  • Run as many cycles as necessary to reach the end of the screen (33,000)
  • Generate the second interrupt

This function is called for each frame but the caller will sleep if needed so that the next frame isn't drawn until 16ms have elapsed (60Hz). You can find this code in sdl2.rs. Without this delay, this is what the game at normal speed will look like, running at about 70Mhz instead of 2Mhz:

space-invaders-2

Note that letting the game run like this for a little while is a good way to test that your code doesn't have any bugs that only show up on the long run...

Despite this, I can't shake the feeling that my Space Invaders is running a bit faster than the original, based on watching some footage of the actual arcade game, but I'm not 100% sure. Feel free to let me know if you find a bug in my timing routine that might explain my impression.

Lessons learned

cpudiag is not enough.

When I wrote my Apple ][ emulator, I first developed the 6502 emulator with a diagnostic file that was extremely thorough, and which gave me a pretty much 100% guarantee that once all these tests pass, my 6502 is flawless and I can now focus on the Apple ][ part without worrying about CPU bugs. I started this project with the same assumption and it was a mistake. Deep into the development, I was displaying graphics that made no sense and after hours of disassembling and understanding what the 8080 code actually does, I ended up finding two CPU bugs which cpudiag had not found.

And one of them was really trivial: I hadn't implemented the MOV E,A instruction correctly. This is a very simple instruction which moves the content of A into E, but I made a typo in my code and moved it into D instead... The other bug was in my implementation of DAD.

Moral of the story: you might have to add tests of your own, and at any rate, you cannot embark on such a project without developing a fluent ability to understand the assembly you are emulating.

Graphics in Rust are still not quite there.

It's becoming a meme now that Rust is struggling in the graphics library department (exhibit A) and in the game department (exhibit B). Finding a library that would make it easy for me to implement this project with very simple requirements (basically just need a frame buffer, possibly some simple GUI widgets) took me way too long. I ended up settling on SDL 2, but the bottom line is that developing GUI's and graphics in Rust on Windows is not exactly a walk in the park.

Next steps

I'm probably done with this project but if I were to come back to it to improve it, I would probably:

  • Make it run in the browser with WASM
  • Sound
  • The graphics still seem a bit janky to me, I'm probably doing something wrong in the SDL 2 event handling
  • Make it do less busy waiting
  • Show the controls so the user doesn't have to guess
  • Add a debugger, breakpoints, etc...

Resources

The following documentation was invaluable to pull off this fun project:

You might also like...
Rust language bindings for TensorFlow
Rust language bindings for TensorFlow

TensorFlow Rust provides idiomatic Rust language bindings for TensorFlow. Notice: This project is still under active development and not guaranteed to

Machine learning crate for Rust

rustlearn A machine learning package for Rust. For full usage details, see the API documentation. Introduction This crate contains reasonably effectiv

Rust bindings for the C++ api of PyTorch.

tch-rs Rust bindings for the C++ api of PyTorch. The goal of the tch crate is to provide some thin wrappers around the C++ PyTorch api (a.k.a. libtorc

个人的 rust 学习资料

🔝 通知: 项目文档迁移到: https://github.com/higker/learn-rust learning-rust-zh 个人的 rust 学习资料 学习目录 目录 源代码地址 相关解析 第一个rust程序 https://github.com/higker/learning-ru

Distributed compute platform implemented in Rust, and powered by Apache Arrow.
Distributed compute platform implemented in Rust, and powered by Apache Arrow.

Ballista: Distributed Compute Platform Overview Ballista is a distributed compute platform primarily implemented in Rust, powered by Apache Arrow. It

Tensors and differentiable operations (like TensorFlow) in Rust

autograd Differentiable operations and tensors backed by ndarray. Motivation Machine learning is one of the field where Rust lagging behind other lang

Rust numeric library with R, MATLAB & Python syntax

Peroxide Rust numeric library contains linear algebra, numerical analysis, statistics and machine learning tools with R, MATLAB, Python like macros. W

A fast, safe and easy to use reinforcement learning framework in Rust.
A fast, safe and easy to use reinforcement learning framework in Rust.

RSRL (api) Reinforcement learning should be fast, safe and easy to use. Overview rsrl provides generic constructs for reinforcement learning (RL) expe

Neural networks in Rust

deeplearn-rs Deep learning in Rust! This is my first shot at this. It's mostly just a proof of concept right now. The API will change. Status We have

Owner
Cedric Beust
Creator of Android Gmail.
Cedric Beust
A stable, linearithmic sort in constant space written in Rust

A stable, linearithmic sort in constant space written in Rust. Uses the method described in "Fast Stable Merging And Sorting In Constant Extra Space"

Dylan MacKenzie 4 Mar 30, 2022
TopK algorithm implementation in Rust (Filtered Space-Saving)

TopK TopK algorithm implementation in Rust. This crate currently provides the Filtered Space-Saving algorithm. Version numbers follow the semver conve

null 6 Feb 24, 2023
Hamming Weight Tree from the paper Online Nearest Neighbor Search in Hamming Space

hwt Hamming Weight Tree from the paper Online Nearest Neighbor Search in Hamming Space To understand how the data structure works, please see the docs

Rust Computer Vision 7 Oct 9, 2021
Msgpack serialization/deserialization library for Python, written in Rust using PyO3, and rust-msgpack. Reboot of orjson. msgpack.org[Python]

ormsgpack ormsgpack is a fast msgpack library for Python. It is a fork/reboot of orjson It serializes faster than msgpack-python and deserializes a bi

Aviram Hassan 139 Dec 30, 2022
Practice repo for learning Rust. Currently going through "Rust for JavaScript Developers" course.

rust-practice ?? Practice repo for learning Rust. Directories /rust-for-js-dev Files directed towards "Rust for JavaScript Developers" course. Thank y

Sammy Samkough 0 Dec 25, 2021
A Rust library with homemade machine learning models to classify the MNIST dataset. Built in an attempt to get familiar with advanced Rust concepts.

mnist-classifier Ideas UPDATED: Finish CLI Flags Parallelize conputationally intensive functions Class-based naive bayes README Image parsing Confusio

Neil Kaushikkar 0 Sep 2, 2021
🦀Rust Turkiye - Rust Dersleri

Rust Turkiye - Rust Dersleri CURIOSITY - Featuring Richard Feynman Bu repo Rust Turkiye tarafindan duzenlenen Rust Dersleri egitiminin alistirma ve ko

Theo M. Bulut 12 Jan 14, 2023
A Rust machine learning framework.

Linfa linfa (Italian) / sap (English): The vital circulating fluid of a plant. linfa aims to provide a comprehensive toolkit to build Machine Learning

Rust-ML 2.2k Jan 2, 2023
Machine Learning library for Rust

rusty-machine This library is no longer actively maintained. The crate is currently on version 0.5.4. Read the API Documentation to learn more. And he

James Lucas 1.2k Dec 31, 2022
Rust library for Self Organising Maps (SOM).

RusticSOM Rust library for Self Organising Maps (SOM). Using this Crate Add rusticsom as a dependency in Cargo.toml [dependencies] rusticsom = "1.1.0"

Avinash Shenoy 26 Oct 17, 2022