chip-8 / chip-8-database

A database of CHIP-8 ROM metadata
Other
17 stars 3 forks source link

CHIP-8 database

A repository full of CHIP-8 metadata

CHIP-8 was created in 1977 by Joseph Weisbecker for an RCA hobby computer called the COSMAC VIP. VIP users quickly started hacking the small, 512-byte interpreter to give it additional features, sharing their alterations and games in the VIPER newsletter.

Over the years, this has resulted in a myriad of different and incompatible CHIP-8 implementations in the wild, and many games require specific versions or combinations of settings to run.

This database allows you to look up those versions and settings so your interpreter can reconfigure itself according to the needs of a given ROM. Without having to bother the user.

How does it work?

When loading a CHIP-8 program, your emulator can calculate a SHA1 hash of the loaded bytes, and look up the hash to retrieve the program name, original platform type and other metadata.

This database is a work in progress. So if you run into ROMs that are not in the database yet, or if you find information that is not correct, please open an issue or a pull request to add them. So that over time this database approaches a reliable and exhaustive list.

Use cases

If you're making a CHIP-8 emulator, here are some suggestions and use cases where this database can come in handy:

Contents

The database consists of four JSON files, each with their own structure:

JSON file Definition Description
programs.json JSON schema Contains information about CHIP-8 programs and ROMs, like name, author, date of release, which different ROMs exist for the same program, what platforms those ROMs were written for, which keys are used and much more.
sha1-hashes.json JSON schema Contains a mapping of SHA1 hashes to indices in the programs.json file, for looking up a binary.
platforms.json JSON schema Contains a list of platforms that the programs in programs.json were written for. Each program lists which platforms it supports, which you can then look up in this file.
quirks.json JSON schema Contains a list of "quirks", which are differences in behaviour between different platforms. Platforms not only differ in features and instruction set, but also in the way the interpret the instructions. These differences are described in this file, and referenced in platforms.json (and sometimes in programs.json).

See the JSON schema definition files for detailed information on each field in each file.

How to use the CHIP-8 database

Querying the CHIP-8 database is done in five steps:

  1. Calculate the SHA1 hash of a ROM file
  2. Look up the SHA1 hash in sha1-hashes.json, which gives you an index
  3. Use the index to find the program metadata in the programs.json file
  4. Find the ROM metadata in the roms list of the program metadata
  5. Configure your interpreter to run the ROM using platforms.json and quirks.json

If you're the kind of person who just wants to see some code, check out the examples in this repository. Otherwise, read on!

Example: Space Invaders

Let's walk through all five steps for the original Space Invaders ROM by David Winter. First, we have to take the SHA1 hash over all the bytes in the ROM. This results in this hash:

5c28a5f85289c9d859f95fd5eadbdcb1c30bb08b

Next, we look this hash up in sha1-hashes.json, and at the time of writing this results in the value 65. This may be a different value when you're going through these steps. The sha1-hashes.json file gets generated from the data in programs.json, and it changes when that file changes.

{
  ...
  "726cb39afa7e17725af7fab37d153277d86bff77": "63",
  "ed829190e37815771e7a8c675ba0074996a2ddb0": "64",
  "5c28a5f85289c9d859f95fd5eadbdcb1c30bb08b": "65", // <-- here it is!
  "f100197f0f2f05b4f3c8c31ab9c2c3930d3e9571": "65",
  "1bd92042717c3bc4f7f34cab34be2887145a6704": "66",
  ...
}

Then, because we found the value 65, we look up the 65th entry in the array in programs.json, and we find this:

{
  "title": "Space Invaders",
  "description": "Space Invaders (1978), by David Winter\n\nThe well known game. Destroy the invaders with your ship. Shoot with 5, move with 4 and 6. Press 5 to begin a game.",
  "authors": ["David Winter"],
  "release": "1996",
  "roms": {
    "5c28a5f85289c9d859f95fd5eadbdcb1c30bb08b": {
      "file": "Space Invaders [David Winter].ch8",
      "platforms": ["superchip"],
      "embeddedTitle": "SPACE INVADERS 0.91 By David WINTER",
      "keys": {
        "left": 4,
        "right": 6,
        "a": 5
      }
    },
    "f100197f0f2f05b4f3c8c31ab9c2c3930d3e9571": {
      "file": "Space Invaders [David Winter] (alt).ch8",
      "platforms": ["superchip"],
      "keys": {
        "left": 4,
        "right": 6,
        "a": 5
      }
    }
  }
}

This program object gives us the title, the author and year of release as well as a description. For other ROMs there may be more fields. See the JSON schema files in the table above for all properties in the different files.

It also contains a property called roms, which maps SHA1 hashes to a ROM object. As you can see, the hash for our ROM maps to the first object:

{
  "file": "Space Invaders [David Winter].ch8",
  "platforms": ["superchip"],
  "embeddedTitle": "SPACE INVADERS 0.91 By David WINTER",
  "keys": {
    "left": 4,
    "right": 6,
    "a": 5
  }
}

This ROM object gives us even more information about this specific ROM, like the platforms that it can run on, the keypad or keyboard mappings to play the game, how the title is originally embedded in the binary, the desired tick rate, the colors to use and more.

Note that if there are multiple entries in the platforms list, they are sorted by "most desired to least desired". For example; if a game was written for Superchip, but it happens to run just as well on regular CHIP-8, then Superchip will come first because that is more "canonical". If a game runs on Superchip, but it has a few minor bugs in Superchip that don't show up when you run it as XO-CHIP, then XO-CHIP will be first in the list. So in that case: if you support XO-CHIP, use that. Otherwise, it's also fine to fall back to Superchip.

Finally, we use the chosen platform and the other metadata in the ROM object to configure our interpreter. The platforms.json and quirks.json files may be of help here.

The platforms list in the ROM object references IDs of platforms from the file platforms.json. If we look at the definition for superchip, which is the platform we need for Space Invaders, we find this:

{
  "id": "superchip",
  "name": "Superchip 1.1",
  "description": "Superchip 1.1 is the platform that most \"superchip\" interpreters implement, because it is the latest version and also because the difference between Superchip version 1.0 and 1.1 is pretty small. This version is faster than its predecessor and adds scroll instructions and a large numeric font. It does however introduces a new quirk by not incrementing the index register when reading or writing registers to memory.",
  "release": "1991-05-24",
  "authors": ["Erik Bryntse"],
  "displayResolutions": ["64x32", "128x64"],
  "defaultTickrate": 30,
  "quirks": {
    "shift": true,
    "memoryLeaveIUnchanged": true,
    "wrap": false,
    "jump": true,
    "vblank": false,
    "logic": false
  }
}

We see that we can find some generic information about the platform that we could show to the user of our interpreter. It also holds the resolutions, "quirks" and default tick rate. The Space Invaders ROM does not explicitly specify a desired tick rate, so we can use this default one from the platform.

The quirks reference IDs in the file quirks.json. Let's take the shift quirk as an example:

{
  "id": "shift",
  "name": "Shift quirk",
  "description": "On most systems the shift opcodes take `vY` as input and stores the shifted version of `vY` into `vX`. The interpreters for the HP48 took `vX` as both the input and the output, introducing the shift quirk.",
  "default": false,
  "ifTrue": "Opcodes `8XY6` and `8XYE` take `vX` as both input and output",
  "ifFalse": "Opcodes `8XY6` and `8XYE` take `vY` as input and `vX` as output"
}

This tells us that we need to reconfigure the input register for the shift opcodes to properly interpret Superchip.

So in the end, we can use all of this information to properly configure our interpreter, and we can show the user that they have just loaded the game Space Invaders from 1996 by David Winter.

And when they press play, everything just runs like magic 🪄

Where to find games

Note that this repository doesn't actually host any games, only metadata! Here are some places you can find the games listed in this database:

Contributing

The CHIP-8 database is always a work in progress. So if you run into ROMs that are not in the database yet, or if you find information that is not correct, please open an issue or a pull request to add them. So that over time this database approaches a reliable and exhaustive list.

The database files are automatically checked for each pull request. Github will complain about your pull request if it does not adhere to the schema definitions or the style guidelines. So don't be afraid to try things if you're not sure how it should be; nobody will accidentally merge a malformed pull request.

Prerequisites

This project uses NPM to manage dependencies and run scripts, including jsonschema and Prettier. Follow the instructions to download and install npm on your system.

Once NPM is installed, navigate to the root of this repository and execute npm install to install this project's dependencies.

Adding a new program

Edit programs.json and add a new object at the end of the array. If you insert a new item in the middle (i.e. alphabetically) it will change existing data that comes afterward, and make the pull request harder to review.

You can start by copying this and filling in the blanks:

{
  "title": "ENTER TITLE HERE",
  "description": "ENTER DESCRIPTION THAT DESCRIBES THIS PROGRAM HERE",
  "release": "ENTER YEAR/DATE OF RELEASE HERE",
  "authors": ["ENTER NAME OF AUTHOR HERE"],
  "roms": {
    "ENTER SHA1 HASH OF ROM FILE HERE": {
      "platforms": ["ENTER PLATFORM HERE"]
    }
  }
}

To create the SHA1 hash, you can use sha1sum, or if your operating system does not supply it, run our helper script like so:

npm run hash path/to/somefile.ch8

The release field may be a year (YYYY) a year and a month (YYYY-MM) or a full date (YYYY-MM-DD).

The platforms field is a list that may contain one or more of these platform IDs:

See platforms.json for more information about these platforms, so you can make an informed choice.

The platforms list should be in order of "most desired to least desired". For example; if a game was written for Superchip, but it happens to run just as well on regular CHIP-8, then Superchip should come first because that is more "canonical". If a game runs on Superchip, but it has a few minor bugs in Superchip that don't show up when you run it as XO-CHIP, then XO-CHIP should be first in the list.

If you are familiar with JSON Schema, review schemas/programs.json for more information on type definitions and validation info.

Once you're done making your changes, run npm start and ensure npm test passes before committing.

Updating the Database from the CHIP-8 Archive

To update the database with new entries from the CHIP-8 Archive, use npm run update.

If there are any changes (check with git status or git diff), review the newly generated entries at the end of programs.json and perform any cleanup that needs to occur. In particular, determine appropriate values for the "platforms" section for each newly added program.

Before committing any changes, run npm start and ensure npm test passes.