Skip to content

Commit

Permalink
Merge pull request #14 from Timendus/superchip-has-vblank
Browse files Browse the repository at this point in the history
v4.1 release
  • Loading branch information
Timendus authored Nov 13, 2023
2 parents 9ff3560 + 81e8558 commit adb1b38
Show file tree
Hide file tree
Showing 54 changed files with 5,858 additions and 303 deletions.
207 changes: 178 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,31 @@
# CHIP-8 test suite

_A collection of ROM images with tests that will aid you in developing your own
CHIP-8, SCHIP or XO-CHIP interpreter (or "emulator")_
CHIP-8, SUPER-CHIP or XO-CHIP interpreter (or "emulator")_

## Table of contents

* [Introduction](#introduction)
* [Baseline](#baseline)
* [Available tests](#available-tests)
* [CHIP-8 splash screen](#chip-8-splash-screen)
* [IBM logo](#ibm-logo)
* [Corax+ opcode test](#corax-opcode-test)
* [Flags test](#flags-test)
* [Quirks test](#quirks-test)
* [Keypad test](#keypad-test)
* [Beep test](#beep-test)
* [Scrolling test](#scrolling-test)
* [Contributing](#contributing)
* [Community response 😄](#community-response-)

# Introduction

I found it hard to find reliable sources on what is the right behaviour and what
is not, especially with the subtle differences between the original "Cosmac VIP"
CHIP-8 and the HP84's SCHIP (or "superchip"). Now that I have written and ported
a couple of interpreters as well as a few programs and games for the platform, I
thought it was time to put that knowledge into code.
CHIP-8 and the HP48's SUPER-CHIP (or "S-CHIP"). Now that I have written and
ported a couple of interpreters as well as a few programs and games for the
platform, I thought it was time to put that knowledge into code.

If you're having issues with your interpreter, you can find help in the [EmuDev
discord channel `#chip-8`](https://discord.gg/dkmJAes). Every test has a clearly
Expand All @@ -33,6 +36,40 @@ share a screenshot. If you discover a problem with this test ROM itself, feel
free to file an issue or open a pull request. It's open source, licensed under
the GPLv3, and you're welcome to [contribute](#contributing).

# Baseline

Most tests have been written to run equally well on all three major CHIP-8
platforms, unless otherwise specified. The [quirks test](#quirks-test) is the
most interesting one, since it was designed to test the differences between
those three platforms. If the test suite itself is wrong, we're not helping
anyone. So what are we testing the test suite against?

## CHIP-8

There are several good Cosmac VIP emulators, so we can quite faithfully run the
original CHIP-8 interpreter and check the results. We use [Emma
O2](https://www.emma02.hobby-site.com/) and/or
[Cadmium](https://github.com/gulrak/cadmium) in `VIP-CHIP-8` mode to validate
the test suite.

If you have an actual, physical Cosmac VIP and would like to verify the test
suite, let me know! 😄

## SUPER-CHIP

For SUPER-CHIP, the test suite has been tested against real HP48 graphing
calculators, in the various interpreters that exist for that system.
[Gulrak](https://github.com/gulrak) from the CHIP-8 community has both an HP48SX
and an HP48GX, and has been so kind as to check if the test suite ROMs behave as
expected.

## XO-CHIP

The XO-CHIP extension was written by [John
Earnest](https://github.com/johnearnest) and was first implemented in his IDE
slash interpreter Octo. As such, we treat [Octo](http://octo-ide.com/) as the
gold standard for how an XO-CHIP system should behave, and test against that.

# Available tests

## CHIP-8 splash screen
Expand Down Expand Up @@ -242,20 +279,22 @@ for more information on the arithmetic operations and the flags.
* [Run this ROM in Octo](https://timendus.github.io/chip8-test-suite/5-quirks.html)
to see what's supposed to happen

CHIP-8, SCHIP and XO-CHIP have subtle differences in the way they interpret the
bytecode. We often call these differences quirks. This test detects which quirks
your interpreter implements, and if those quirks match the platform you're
trying to target. This is one of the hardest parts to "get right" and often a
reason why "some games work, but some don't".
CHIP-8, SUPER-CHIP and XO-CHIP have subtle differences in the way they interpret
the bytecode. We often call these differences quirks. This test detects which
quirks your interpreter implements, and if those quirks match the platform
you're trying to target. This is one of the hardest parts to "get right" and
often a reason why "some games work, but some don't".

### The menu

The test asks you to choose the platform you are targeting:
The test asks you to choose the platform you are targeting. If you select
SUPER-CHIP, if will then also ask you if you want to test for the "modern" or
the "legacy" behaviour. When in doubt, go for the "modern" one.

![Choosing a target platform in the quirks test](./pictures/quirks-platform.png)

You can press any of the numbers `1` to `3` on the CHIP-8 keypad to jump to the
corresponding test.
You can press any of the numbers `1` to `3` on the CHIP-8 keypad to make the
corresponding selection.

Alternatively, you can move the cursor up and down with CHIP-8 keys `E` and `F`
and select an item with `A`. This feature mainly exists so people implementing
Expand All @@ -264,9 +303,14 @@ can map their buttons to those CHIP-8 keys and have an intuitive interface too.

If you want to repeat a test often or even automate them, having to use the
graphical menu just gets in the way. In that case, you can force this ROM to
select a specific platform by loading a value between `1` and `3` into memory at
select a specific platform by loading a value between `1` and `4` into memory at
the address `0x1FF` (`512`).

* `1` - CHIP-8
* `2` - SUPER-CHIP with modern behaviour
* `3` - XO-CHIP
* `4` - SUPER-CHIP with legacy behaviour

### The test

The test will now run through a couple of steps, which you will see on the
Expand All @@ -280,14 +324,15 @@ or an error) and if that matches your chosen target platform (a checkmark or a
cross).

* `vF reset` - The AND, OR and XOR opcodes (`8xy1`, `8xy2` and `8xy3`) reset the
flags register to zero. Test will show `E1` if the AND and OR tests don't
behave the same and `E2` if the AND and XOR tests don't behave the same.
flags register to zero. Test will show `ERR1` if the AND and OR tests don't
behave the same and `ERR2` if the AND and XOR tests don't behave the same.
* `Memory` - The save and load opcodes (`Fx55` and `Fx65`) increment the index
register. More information [here](https://laurencescotford.net/chip-8-on-the-cosmac-vip-loading-and-saving-variables/) and [here](https://tobiasvl.github.io/blog/write-a-chip-8-emulator/#fx55-and-fx65-store-and-load-memory).
register. More information [here](https://laurencescotford.net/chip-8-on-the-cosmac-vip-loading-and-saving-variables/)
and [here](https://tobiasvl.github.io/blog/write-a-chip-8-emulator/#fx55-and-fx65-store-and-load-memory).
* `Display wait` - Drawing sprites to the display waits for the vertical blank
interrupt, limiting their speed to max 60 sprites per second. More information
[here](https://laurencescotford.net/chip-8-on-the-cosmac-vip-drawing-sprites/).
Test will show `LOW` if the number of cycles per frame is too low for the test
Test will show `SLOW` if the number of cycles per frame is too low for the test
to be deterministic (this is not necessarily an error, but a suggestion to
rerun the test with a higher number of cycles per frame).
* `Clipping` - Sprites drawn at the bottom edge of the screen get clipped
Expand All @@ -296,18 +341,43 @@ cross).
of the screen. This also tests that sprites drawn at coordinates of `x > 63`
and/or `y > 31` wrap around to `x % 64` and `y % 32`. More information
[here](https://laurencescotford.net/chip-8-on-the-cosmac-vip-drawing-sprites/).
Test will show `E1` if the clipping is inconsistent in different dimensions or
wrapping to the wrong coordinates and `E2` if sprites don't wrap around as
expected.
Test will show `ERR1` if the clipping is inconsistent in different dimensions
or wrapping to the wrong coordinates and `ERR2` if sprites don't wrap around
as expected.
* `Shifting` - The shift opcodes (`8xy6` and `8xyE`) only operate on `vX`
instead of storing the shifted version of `vY` in `vX` (more information
[here](https://tobiasvl.github.io/blog/write-a-chip-8-emulator/#8xy6-and-8xye-shift)). Test will show `E1` if the shift opcodes behave differently.
[here](https://tobiasvl.github.io/blog/write-a-chip-8-emulator/#8xy6-and-8xye-shift)).
Test will show `ERR1` if the shift opcodes behave differently.
* `Jumping` - The "jump to some address plus `v0`" instruction (`Bnnn`) doesn't
use `v0`, but `vX` instead where `X` is the highest nibble of `nnn` (more
information [here](https://tobiasvl.github.io/blog/write-a-chip-8-emulator/#bnnn-jump-with-offset))

Note that you need timer support for this test to run.

### SUPER-CHIP / XO-CHIP

If you select SUPER-CHIP or XO-CHIP in the menu, half of the test will be
executed in `hires` mode, and the behaviour of `Display wait` and `Clipping`
will be tested in both `lores` and `hires` modes. This means you will not just
see "on" or "off" for these quirks, but instead one of these values:

* `NONE` - The quirk is disabled in both modes
* `HRES` - The quirk is only enabled in `hires` mode
* `LRES` - The quirk is only enabled in `lores` mode
* `BOTH` - The quirk is enabled in both modes

If the test finds different errors for the `Clipping` test in `hires` mode
compared to `lores` mode, it will show `ERR3`. In that case, first make sure
your modes produce the same wrapping and clipping results, and see which errors
pop up after that.

Wondering why testing `hires` has been added, or if a quirk can ever be enabled
in only one of the modes? Or just wondering why SUPER-CHIP has a "legacy" and a
"modern" version of the test? You can [read the full story
here](./legacy-superchip.md).

### More information

See this [excellent
table](https://chip8.gulrak.net) by Gulrak for
an overview of all the known quirks for the relatively popular CHIP-8 versions.
Expand Down Expand Up @@ -383,7 +453,84 @@ See [this
article](https://laurencescotford.net/chip-8-on-the-cosmac-vip-keyboard-input/)
for more information.

## Contributing
## Beep test

* [Download ROM](https://github.com/Timendus/chip8-test-suite/raw/main/bin/7-beep.ch8)
(source code available [here](./src/tests/7-beep.8o))
* [Run this ROM in Octo](https://timendus.github.io/chip8-test-suite/7-beep.html)
to see what's supposed to happen (sound may not actually play due to browser
restrictions)

This test allows you to test if your buzzer is working. It will beep SOS in
morse code and flash a speaker icon on the display in the same pattern. If you
press the CHIP-8 button `B` it will give you manual control over the buzzer.
Press `B` to beep.

![The beep test beeping](./pictures/beep.png)

## Scrolling test

* [Download ROM](https://github.com/Timendus/chip8-test-suite/raw/main/bin/8-scrolling.ch8)
(source code available [here](./src/tests/8-scrolling.8o))
* [Run this ROM in Octo](https://timendus.github.io/chip8-test-suite/8-scrolling.html)
to see what's supposed to happen

This test is only applicable to SUPER-CHIP and XO-CHIP interpreters, since
regular CHIP-8 does not have scrolling instructions. It will test to see if your
scrolling opcodes scroll the display in the right directions by the right
amounts of pixels. One literal "edge"-case that it does **not** cover is what
happens at the edges of the screen.

### The menu

The test asks you to choose the platform and resolution you are targeting. For
SUPER-CHIP `lores`, it will also ask you to choose between "modern" or "legacy"
behaviour. When in doubt, go for the "modern" one.

![Choosing a target platform in the scrolling test](./pictures/scrolling-platform.png)

You can press any of the numbers `1` or `2` on the CHIP-8 keypad to select the
corresponding entry.

Alternatively, you can move the cursor up and down with CHIP-8 keys `E` and `F`
and select an item with `A`. This feature mainly exists so people implementing
interpreters for platforms with limited input devices (like a game controller)
can map their buttons to those CHIP-8 keys and have an intuitive interface too.

If you want to repeat a test often or even automate them, having to use the
graphical menu just gets in the way. In that case, you can force this ROM to
select a specific platform by loading a value between `1` and `5` into memory at
the address `0x1FF` (`512`).

* `1` - SUPER-CHIP `lores` with modern behaviour
* `2` - SUPER-CHIP `lores` with legacy behaviour
* `3` - SUPER-CHIP `hires`
* `4` - XO-CHIP `lores`
* `5` - XO-CHIP `hires`

### The test

The test will show you a visual with arrows and boxes. If everything works as
expected for the target you have selected, all the arrows will end up in their
boxes, like so:

![Result of the scrolling test for `lores` SUPER-CHIP](./pictures/lores-scrolling.png)

If you have issues with one or more of your scrolling instructions, some arrows
will be (partially) outside their boxes. The arrows all point in the directions
that they should be scrolled in, so the ones that have not moved in the
direction that they point in represent the scrolling instructions that are not
working properly.

For example, this is what you see if none of the scrolling instructions have
been implemented:

![Result of the scrolling test with no implemented scrolling](./pictures/lores-no-scrolling.png)

A note on legacy versus modern behaviour for SUPER-CHIP's `lores` mode can be
found in the document [Legacy SUPER-CHIP](./legacy-superchip.md).

# Contributing

Do you find an issue in this test suite that you think you can fix? Feel free to
submit a PR! Here's how to build the project, assuming you have Nodejs and NPM
Expand All @@ -399,12 +546,14 @@ npm install
npm start

# Build a specific test:
npm run build-logo
npm run build-ibm
npm run build-corax
npm run build-flags
npm run build-quirks
npm run build-keypad
TEST=1-chip8-logo npm run build-test
TEST=2-ibm-logo npm run build-test
TEST=3-corax+ npm run build-test
TEST=4-flags npm run build-test
TEST=5-quirks npm run build-test
TEST=6-keypad npm run build-test
TEST=7-scrolling npm run build-test
TEST=8-beep npm run build-test
```

Note that the `npm` scripts use the MacOS command `pbcopy` to copy
Expand All @@ -416,7 +565,7 @@ not work properly. Edit `package.json` and remove this part from the end of `scr
&& cat bin/${TEST}.8o | pbcopy
```

## Community response 😄
# Community response 😄

[![DUDE THANKS! I was writing a CHIP-8 emulator and THIS HELPED ME SO FRICKING MUCH, THANKS! / same here, this is amazing](./pictures/testimonial1.png)](https://github.com/Timendus/chip8-test-suite/issues/1)

Expand Down
2 changes: 1 addition & 1 deletion bin/1-chip8-logo.8o
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
: splash-3-1
0xce 0xfc 0xf8 0xc0 0xd4 0xdc 0xc4 0xc5 0x00 0x00 0x30 0x44 0x24 0x14 0x63
: splash-4-1
0xf1 0x03 0x07 0x07 0x77 0x57 0x53 0x71 0x00 0x00 0x28 0x8e 0xa8 0xa8 0xa6
0xf1 0x03 0x07 0x07 0x27 0x67 0x23 0x71 0x00 0x00 0x28 0x8e 0xa8 0xa8 0xa6
: splash-5-1
0xce 0x87 0x03 0x03 0x03 0x87 0xfe 0xfc 0x00 0x00 0x60 0x90 0xf0 0x80 0x70

Binary file modified bin/1-chip8-logo.ch8
Binary file not shown.
2 changes: 1 addition & 1 deletion bin/2-ibm-logo.8o
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,5 @@
: ibm-4-0
0x03 0x00 0x07 0x00 0x0f 0x00 0xbf 0x00 0xfb 0x00 0xf3 0x00 0xe3 0x00 0x43
: ibm-5-0
0xe5 0x05 0xe2 0x00 0x85 0x07 0x81 0x01 0x80 0x02 0x80 0x07 0xe5 0x05 0xe7
0xe5 0x05 0xe2 0x00 0x85 0x07 0x81 0x01 0x80 0x02 0x80 0x02 0xe6 0x02 0xe7

Binary file modified bin/2-ibm-logo.ch8
Binary file not shown.
2 changes: 1 addition & 1 deletion bin/3-corax+.8o
Original file line number Diff line number Diff line change
Expand Up @@ -416,5 +416,5 @@
: version-0-0
0x0a 0xae 0xa2 0x42
: version-1-0
0x38 0x28 0x28 0xb8
0x10 0x30 0x10 0xb8

Binary file modified bin/3-corax+.ch8
Binary file not shown.
28 changes: 27 additions & 1 deletion bin/4-flags.8o
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,28 @@

# Subtraction in one direction (no carry)
opcode-digit 0x5 # 0x85
# Edge cases:
# Check that vF -= vX results in no carry
vF := 20
vF -= 15_in_a_register # 5 (0x05), but should be overwritten by flag, so 1
v4 := vF
# Check that vX -= vF results in the correct result and no carry
v3 := 20
vF := 15
v3 -= vF # 5 (0x05)
# Check that N - N (for the same N) does not result in carry
v5 := 10
vF := 10
v5 -= vF
v5 := vF
# Base case: check that subtracting two regular registers results in the
# correct value and no carry set, and that the carry register actually gets
# overwritten.
vF := 0xAA
v2 := 50
v2 -= 15_in_a_register # 35 (0x23)
# Check all our assertions
if v5 != 1 then vF := 2
expect-v2-vf-v3-v4 35 1 5 1

y += 5
Expand All @@ -214,16 +227,29 @@

# Subtraction in the other direction (no carry)
opcode-digit 0x7 # 0x87
# Edge cases:
# Check that vF =- vX results in no carry
vF := 10
vF =- 15_in_a_register # 5 (0x5), but should be overwritten by flag, so 1
v4 := vF
# Check that vX =- vF results in the correct result and no carry
v3 := 15
vF := 20
v3 =- vF # 5 (0x05)
# Check that N - N (for the same N) does not result in carry
v5 := 10
vF := 10
v5 =- vF
v5 := vF
# Base case: check that subtracting two regular registers results in the
# correct value and no carry set, and taht the carry register actually gets
# overwritten.
vF := 0xAA
v2 := 15
v1 := 50
v2 =- v1 # 35 (0x23)
# Check all our assertions
if v5 != 1 then vF := 2
expect-v2-vf-v3-v4 35 1 5 1
x += 1

Expand Down Expand Up @@ -528,5 +554,5 @@
: version-0-0
0x0a 0xae 0xa2 0x42
: version-1-0
0x38 0x28 0x28 0xb8
0x10 0x30 0x10 0xb8

Binary file modified bin/4-flags.ch8
Binary file not shown.
Loading

0 comments on commit adb1b38

Please sign in to comment.