Click on the images above to play the games in your web browser.
The games are from Frédéric Devernay's SVision-8 website.
Controls are through the keyboard, so unfortunately you can't play on a tablet device at the moment.
I was born in the early 1980s, and my earliest memories of computers are from IBM PC clones that my dad brought home in the mid 1980's. Alternative home computers, such as the Apple II and the Commodore 64, weren't that well known or common in South Africa.
What I'm trying to say is that I don't have any real experience with computers that came before the IBM clones, but I always enjoy reading up on the subject. So I was pleasantly amused to learn of CHIP-8, a virtual machine for playing video games from the mid-1970s. It was originally invented by Joseph Weisbecker.
It dates back to a time when users were still expected to assemble their computers from the discrete components themselves. In fact I've never even heard of the computers on which it originally ran: The COSMAC VIP and Telmac 1800.
The Wikipedia page describes CHIP-8 as a programming language, but that's a bit generous. CHIP-8 is more of a specification for a virtual machine that defines a set of instructions and an environment in which to interpret them.
To program in CHIP-8 you actually have to input the individual machine codes in hexadecimal. In other words you have to assemble your programs by hand, on paper, before entering the binary code into your computer.
The CHIP-8 environment has a 64×32 pixel display with monochrome graphics. CHIP-8 programs don't draw individual pixels, but rather copy sprites to the display memory.
Its sound consists of a single tone, the frequency of which depends on the implementation. The developer only gets to control the duration of the beep.
Games are limited to 4KB for the code and graphics.
In spite of these limitations, there is still a community of enthusiasts around it. There is also wide variety of games available for it, mostly simple games like Pong, Space Invaders and Tetris clones.
All in all, it is like stone age Flash: A cross-platform environment in which a variety of different games can be run.
Naturally I wanted such an interpreter of my own. I've now finished it, and I've placed the source code on GitHub: https://github.com/wernsey/chip8
The primary version uses the Simple DirectMedia Layer (SDL) (version 2) for managing the graphics. It has the advantage of being portable to a variety of operating systems. I've compiled and tested it on Windows and Linux and in web browsers.
The web browser version was created by compiling the C code to JavaScript with Emscripten.
At the moment there are some caveats to running it in a web browser. The most important being that
if you want to run a new CHIP-8 binary file you have to recompile the entire interpreter
because it uses Emscripten's --preload-file
to store the CHIP-8 program in a format that can be
read by the JavaScript.
Under Windows, there is also a second version that uses only Win32 (the Windows API) calls drawing the screen only with GDI (Graphics Device Interface) calls. This version has no third party dependencies, so it is easy to redistribute.
My interpreter also supports the SuperChip instructions, which is an extension of the original with a higher resolution graphics mode.
The interpreter also has a debugger. You can press F5 in a running program or start the interpreter
with the -d
command-line option. When in debug mode, press F6 to step through the code and
F8 to resume the program (F7 would've been used for "step into", but CHIP-8 has no notion of function
calls).
Here is a screenshot of the interpreter with the debugger active:
Because it is 2016 and assembling your code by hand is so old fashioned, I've also implemented an assembler. The syntax is based on the syntax described in Cowgod's Chip-8 Technical Reference v1.0, by Thomas P. Greene.
The following is an example of a program that draws a companion cube bouncing horizontally across the screen:
; Companion Cube Sample program. Disregard its advice.
; Define some more human-friendly names for the registers
define boxx V0 ; Sprite X,Y position
define boxy V1
define oldx V2 ; Previous sprite X,Y position
define oldy V3
define dirx V4 ; Sprite direction
define diry V5
define tmp VE
; Clear the screen
CLS
; Load the variables' initial values
LD boxx, 1
LD dirx, 1
LD boxy, 10
LD I, sprite1
DRW boxx, boxy, 8
LD tmp, 1
; The main loop
loop:
; Store the current position
LD oldx, boxx
LD oldy, boxy
; If the X direction is 0, go to sub1...
SE dirx, 0
JP sub1
; ...otherwise add 1 to the box' position
ADD boxx, 1
; If you reached the right edge of the screen, change direction
SNE boxx, 56
LD dirx, 1
jp draw1
sub1:
; subtract 1 from the box' position
SUB boxx, tmp
; If you reached the left edge of the screen, change direction
SNE boxx, 0
LD dirx, 0
; Draw the box
draw1:
; Load the address of the sprite's graphics into register I
LD I, sprite1
; Erase the sprite at the old position
DRW oldx, oldy, 8
; Draw the sprite at the new position
DRW boxx, boxy, 8
; Return to the start of the loop
JP loop
; Binary data of the sprite.
; 1s represent pixels to be drawn, 0s are blank pixels.
sprite1:
db %01111110,
%10000001,
%10100101,
%10111101,
%10111101,
%10011001,
%10000001,
%01111110,
To assemble the file, run the command ./c8asm -o GAMES/CUBE.ch8 cube.asm
Finally, I've also implemented a disassembler. It actually started as a program to test the assembler output, but it was fairly simple to convert it to a proper disassembler.
To run the disassembler, just run the command ./c8dasm GAMES/CUBE.ch8
Here are some references for further reading: