diff --git a/README.md b/README.md
index 919467b..b1b5bd4 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,12 @@
# 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)
@@ -15,6 +16,8 @@ CHIP-8, SCHIP or XO-CHIP interpreter (or "emulator")_
* [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-)
@@ -22,9 +25,9 @@ CHIP-8, SCHIP or XO-CHIP interpreter (or "emulator")_
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
@@ -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
@@ -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
@@ -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)
diff --git a/bin/1-chip8-logo.8o b/bin/1-chip8-logo.8o
index 8fd459b..da2b4e9 100644
--- a/bin/1-chip8-logo.8o
+++ b/bin/1-chip8-logo.8o
@@ -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
diff --git a/bin/1-chip8-logo.ch8 b/bin/1-chip8-logo.ch8
index 4213638..8f83105 100644
Binary files a/bin/1-chip8-logo.ch8 and b/bin/1-chip8-logo.ch8 differ
diff --git a/bin/2-ibm-logo.8o b/bin/2-ibm-logo.8o
index 384e58d..3470889 100644
--- a/bin/2-ibm-logo.8o
+++ b/bin/2-ibm-logo.8o
@@ -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
diff --git a/bin/2-ibm-logo.ch8 b/bin/2-ibm-logo.ch8
index 6835560..d60dac8 100644
Binary files a/bin/2-ibm-logo.ch8 and b/bin/2-ibm-logo.ch8 differ
diff --git a/bin/3-corax+.8o b/bin/3-corax+.8o
index ca0608d..6d23690 100644
--- a/bin/3-corax+.8o
+++ b/bin/3-corax+.8o
@@ -416,5 +416,5 @@
: version-0-0
0x0a 0xae 0xa2 0x42
: version-1-0
- 0x38 0x28 0x28 0xb8
+ 0x10 0x30 0x10 0xb8
diff --git a/bin/3-corax+.ch8 b/bin/3-corax+.ch8
index 60ae95b..317029b 100644
Binary files a/bin/3-corax+.ch8 and b/bin/3-corax+.ch8 differ
diff --git a/bin/4-flags.8o b/bin/4-flags.8o
index ad44936..c496d7a 100644
--- a/bin/4-flags.8o
+++ b/bin/4-flags.8o
@@ -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
@@ -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
@@ -528,5 +554,5 @@
: version-0-0
0x0a 0xae 0xa2 0x42
: version-1-0
- 0x38 0x28 0x28 0xb8
+ 0x10 0x30 0x10 0xb8
diff --git a/bin/4-flags.ch8 b/bin/4-flags.ch8
index 97a73c6..431f3b0 100644
Binary files a/bin/4-flags.ch8 and b/bin/4-flags.ch8 differ
diff --git a/bin/5-quirks.8o b/bin/5-quirks.8o
index f3cf962..5d9eade 100644
--- a/bin/5-quirks.8o
+++ b/bin/5-quirks.8o
@@ -158,26 +158,52 @@
return
-:macro show X address {
- v0 := X
- i := address
- sprite v0 v1 15
-}
+:const OFF 0
+:const ON 1
+:const BOTH 2
+:const NONE 3
+:const LORES 4
+:const HIRES 5
+:const ERR1 6
+:const ERR2 7
+:const ERR3 8
+
+:const CHIP8 1
+:const SCHIP_MODERN 2
+:const XOCHIP 3
+:const SCHIP_LEGACY 4
: main
clear
i := 0x1FF
load v0
- if v0 == 1 then jump quirks-chip8
- if v0 == 2 then jump quirks-schip
- if v0 == 3 then jump quirks-xochip
+ if v0 == CHIP8 then jump quirks-chip8
+ if v0 == SCHIP_MODERN then jump quirks-schip
+ if v0 == SCHIP_LEGACY then jump quirks-schip-legacy
+ if v0 == XOCHIP then jump quirks-xochip
text 6 2 quirks-choose
- text 16 10 quirks-str-chip8
- text 16 15 quirks-str-schip
- text 16 20 quirks-str-xochip
+ text 10 10 quirks-str-chip8
+ text 10 15 quirks-str-schip
+ text 10 20 quirks-str-xochip
+ render-version
+
+ :unpack 0xA quirks-menu
+ v2 := 2
+ jump menu-start
+
+: superchip-menu
+ clear
+ text 10 2 quirks-choose-superchip
+ text 18 12 quirks-str-modern
+ text 18 17 quirks-str-legacy
+ render-version
- # Show version number in bottom right corner
+ :unpack 0xA superchip-target-menu
+ v2 := 1
+ jump menu-start
+
+: render-version
x := 50
y := 27
i := version-0-0
@@ -185,81 +211,94 @@
x := 58
i := version-1-0
sprite x y 4
+ return
- :unpack 0xA quirks-menu
- v2 := 2
- jump menu-start
: quirks-chip8
i := scratchpad
- v0 := 1
+ v0 := CHIP8
save v0
jump quirks-run-tests
: quirks-schip
i := scratchpad
- v0 := 2
+ v0 := SCHIP_MODERN
+ save v0
+ jump quirks-run-tests
+
+: quirks-schip-legacy
+ i := scratchpad
+ v0 := SCHIP_LEGACY
save v0
jump quirks-run-tests
: quirks-xochip
i := scratchpad
- v0 := 3
+ v0 := XOCHIP
save v0
: quirks-run-tests
waitKeyRelease
+ clear
# Determine frames per second for dispQuirk
- clear
+ i := scratchpad
+ load v0
+ if v0 == CHIP8 begin
+ get-frames-per-second-chip8
- v1 := 0
- show 8 splash-0-0
- show 16 splash-1-0
- show 24 splash-2-0
- show 32 splash-3-0
- show 40 splash-4-0
- show 48 splash-5-0
-
- v1 := 15
- show 8 splash-0-1
- show 16 splash-1-1
- show 24 splash-2-1
- show 32 splash-3-1
- show 40 splash-4-1
- show 48 splash-5-1
+ # We expect the inner loop with 30 `sprite`s to have been able to run six
+ # times in the timespan of 180 interrupts
+ v0 := ON
+ if v3 != 0 then v0 := OFF
+ if v2 > 6 then v0 := OFF
+ if v2 < 6 then v0 := ERR1
+ i := scratchpad-plus-1
+ save v0
+ else # Superchip & XO-CHIP
+ get-frames-per-second-schip-xochip
- i := quirks-values
- load v6
- i := quirks-image
- delay := v5
- loop
- v5 := 30
- loop
- sprite v0 v1 1
- if vF == 0 begin
- v0 := 54
- v6 := delay
- v6 >>= v6
- v6 >>= v6
- v0 -= v6
- end
- v5 -= 1
- if v5 != 0 then
- again
- v2 += v4
- v3 += vF
- vE := delay
- if vE != 0 then again
+ # We expect the inner loop with 30 `sprite`s to have been able to run 3
+ # times in the timespan of 90 interrupts
+ v0 := ON
+ if v3 != 0 then v0 := OFF
+ if v2 > 3 then v0 := OFF
+ if v2 < 3 then v0 := ERR1
+ i := scratchpad-plus-1
+ save v0
- # We expect the inner loop with 30 `sprite`s to have been able to run six
- # times in the timespan of 180 interrupts
- v0 := 1
- if v3 != 0 then v0 := 0
- if v2 > 6 then v0 := 0
- if v2 < 6 then v0 := 2
- i := scratchpad-plus-1
- save v0
+ # Do the test again, but now in hires mode
+ hires
+ clear
+ get-frames-per-second-hires
+
+ # We expect the inner loop with 30 `sprite`s to have been able to run 3
+ # times in the timespan of 90 interrupts
+ v1 := ON
+ if v3 != 0 then v1 := OFF
+ if v2 > 3 then v1 := OFF
+ if v2 < 3 then v1 := ERR1
+ i := scratchpad-plus-1
+ load v0
+ if v0 == ERR1 then jump quirks-combined-vblank-skip
+ if v1 == ERR1 begin
+ v0 := ERR1
+ jump quirks-combined-vblank-skip
+ end
+ if v0 == OFF begin
+ if v1 == OFF then v0 := NONE
+ if v1 == ON then v0 := HIRES
+ end
+ if v0 == ON begin
+ if v1 == OFF then v0 := LORES
+ if v1 == ON then v0 := BOTH
+ end
+: quirks-combined-vblank-skip
+ i := scratchpad-plus-1
+ save v0
+
+ lores
+ end
# Determine if sprites get clipped vertically
clear
@@ -309,17 +348,116 @@
v9 += vF
# Save result
- v0 := 0
+ v0 := OFF
# Clipping
- if v5 == 0 then v0 := 1
- if v5 != v6 then v0 := 2
- if v5 != v7 then v0 := 2
- if v5 != v8 then v0 := 2
+ if v5 == 0 then v0 := ON
+ if v5 != v6 then v0 := ERR1
+ if v5 != v7 then v0 := ERR1
+ if v5 != v8 then v0 := ERR1
# Wrapping
- if v9 != 4 then v0 := 3
+ if v9 != 4 then v0 := ERR2
i := scratchpad-plus-2
save v0
+ # If SuperCHIP or XO-CHIP, do it again in hires
+ i := scratchpad
+ load v0
+ if v0 != CHIP8 begin
+ hires
+ # Determine if sprites get clipped vertically
+ clear
+ i := cursor
+ v0 := 60
+ v1 := 61
+ sprite v0 v1 6
+ v0 := 54
+ v1 := 2
+ sprite v0 v1 2
+ v5 := vF
+ v0 := 66
+ sprite v0 v1 2
+ v6 := vF
+
+ # Determine if sprites get clipped horizontally
+ clear
+ i := cursor
+ v0 := 125
+ v1 := 5
+ sprite v0 v1 6
+ v0 := 3
+ v1 := 4
+ sprite v0 v1 2
+ v7 := vF
+ v1 := 10
+ sprite v0 v1 2
+ v8 := vF
+
+ # Determine if sprites get wrapped (both directions)
+ clear
+ v0 := 174
+ v1 := 82
+ sprite v0 v1 6 # Should draw at 46,18
+ v0 := 40
+ v1 := 17
+ sprite v0 v1 2
+ v9 := vF
+ v0 := 52
+ sprite v0 v1 2
+ v9 += vF
+ v1 := 23
+ sprite v0 v1 2
+ v9 += vF
+ v0 := 40
+ sprite v0 v1 2
+ v9 += vF
+
+ # Determine result
+ v1 := OFF
+ # Clipping
+ if v5 == 0 then v1 := ON
+ if v5 != v6 then v1 := ERR1
+ if v5 != v7 then v1 := ERR1
+ if v5 != v8 then v1 := ERR1
+ # Wrapping
+ if v9 != 4 then v1 := ERR2
+
+ # Compare with previous result
+ i := scratchpad-plus-2
+ load v0
+
+ if v0 == ERR1 begin
+ if v1 == ERR1 then jump quirks-combined-wrapping-skip
+ v0 := ERR3
+ jump quirks-combined-wrapping-skip
+ end
+ if v0 == ERR2 begin
+ if v1 == ERR2 then jump quirks-combined-wrapping-skip
+ v0 := ERR3
+ jump quirks-combined-wrapping-skip
+ end
+ if v1 == ERR1 begin
+ v0 := ERR3
+ jump quirks-combined-wrapping-skip
+ end
+ if v1 == ERR2 begin
+ v0 := ERR3
+ jump quirks-combined-wrapping-skip
+ end
+
+ if v0 == ON begin
+ if v1 == ON then v0 := BOTH
+ if v1 == OFF then v0 := LORES
+ end
+ if v0 == OFF begin
+ if v1 == ON then v0 := HIRES
+ if v1 == OFF then v0 := NONE
+ end
+: quirks-combined-wrapping-skip
+ i := scratchpad-plus-2
+ save v0
+ lores
+ end
+
# Present results
clear
@@ -342,8 +480,7 @@
i := scratchpad
load v0
i := flag-err
- if v0 == 1 begin
- # Selected CHIP-8
+ if v0 == CHIP8 begin
if v5 == 1 then i := flag-ok
else
# Selected SCHIP or XO-CHIP
@@ -356,7 +493,7 @@
if v5 == 1 then i := quirks-on
if v5 != v6 then i := quirks-inconsistent-1
if v5 != v7 then i := quirks-inconsistent-2
- vD := 44
+ vD := 42
vE := 1
drawText
@@ -371,11 +508,16 @@
i := scratchpad
load v0
i := flag-err
- if v0 == 2 begin
- # Selected SCHIP
+ if v0 == CHIP8 begin
+ if v5 != 5 then i := flag-ok
+ end
+ if v0 == SCHIP_MODERN begin
if v5 == 5 then i := flag-ok
- else
- # Selected CHIP-8 or XO-CHIP
+ end
+ if v0 == SCHIP_LEGACY begin
+ if v5 == 5 then i := flag-ok
+ end
+ if v0 == XOCHIP begin
if v5 != 5 then i := flag-ok
end
x := 59
@@ -383,7 +525,7 @@
sprite x y 3
i := quirks-on
if v5 == 5 then i := quirks-off
- vD := 44
+ vD := 42
vE := 6
drawText
@@ -393,20 +535,29 @@
i := scratchpad
load v1
i := flag-err
- if v0 == 1 begin
- # Selected CHIP-8
- if v1 == 1 then i := flag-ok
- else
- # Selected SCHIP or XO-CHIP
- if v1 == 0 then i := flag-ok
+ if v0 == CHIP8 begin
+ if v1 == ON then i := flag-ok
+ end
+ if v0 == SCHIP_MODERN begin
+ if v1 == NONE then i := flag-ok
+ end
+ if v0 == SCHIP_LEGACY begin
+ if v1 == LORES then i := flag-ok
+ end
+ if v0 == XOCHIP begin
+ if v1 == NONE then i := flag-ok
end
x := 59
y := 12
sprite x y 3
i := quirks-off
- if v1 == 1 then i := quirks-on
- if v1 == 2 then i := quirks-low
- vD := 44
+ if v1 == ON then i := quirks-on
+ if v1 == ERR1 then i := quirks-slow
+ if v1 == LORES then i := quirks-lores
+ if v1 == HIRES then i := quirks-hires
+ if v1 == BOTH then i := quirks-both
+ if v1 == NONE then i := quirks-none
+ vD := 42
vE := 11
drawText
@@ -416,21 +567,31 @@
i := scratchpad
load v2
i := flag-err
- if v0 == 3 begin
- # Selected XO-CHIP
- if v2 == 0 then i := flag-ok
- else
- # Selected CHIP-8 or SCHIP
- if v2 == 1 then i := flag-ok
+ if v0 == CHIP8 begin
+ if v2 == ON then i := flag-ok
+ end
+ if v0 == SCHIP_MODERN begin
+ if v2 == BOTH then i := flag-ok
+ end
+ if v0 == SCHIP_LEGACY begin
+ if v2 == BOTH then i := flag-ok
+ end
+ if v0 == XOCHIP begin
+ if v2 == NONE then i := flag-ok
end
x := 59
y := 17
sprite x y 3
i := quirks-off
- if v2 == 1 then i := quirks-on
- if v2 == 2 then i := quirks-inconsistent-1
- if v2 == 3 then i := quirks-inconsistent-2
- vD := 44
+ if v2 == ON then i := quirks-on
+ if v2 == LORES then i := quirks-lores
+ if v2 == HIRES then i := quirks-hires
+ if v2 == BOTH then i := quirks-both
+ if v2 == NONE then i := quirks-none
+ if v2 == ERR1 then i := quirks-inconsistent-1
+ if v2 == ERR2 then i := quirks-inconsistent-2
+ if v2 == ERR3 then i := quirks-inconsistent-3
+ vD := 42
vE := 16
drawText
@@ -447,11 +608,16 @@
i := scratchpad
load v0
i := flag-err
- if v0 == 2 begin
- # Selected SCHIP
+ if v0 == CHIP8 begin
+ if v5 != 0 then i := flag-ok
+ end
+ if v0 == SCHIP_MODERN begin
if v5 == 0 then i := flag-ok
- else
- # Selected CHIP-8 or XO-CHIP
+ end
+ if v0 == SCHIP_LEGACY begin
+ if v5 == 0 then i := flag-ok
+ end
+ if v0 == XOCHIP begin
if v5 != 0 then i := flag-ok
end
x := 59
@@ -460,7 +626,7 @@
i := quirks-off
if v5 == 0 then i := quirks-on
if v5 != v7 then i := quirks-inconsistent-1
- vD := 44
+ vD := 42
vE := 21
drawText
@@ -475,11 +641,16 @@
i := scratchpad
load v0
i := flag-err
- if v0 == 2 begin
- # Selected SCHIP
+ if v0 == CHIP8 begin
+ if v5 == 0 then i := flag-ok
+ end
+ if v0 == SCHIP_MODERN begin
if v5 != 0 then i := flag-ok
- else
- # Selected CHIP-8 or XO-CHIP
+ end
+ if v0 == SCHIP_LEGACY begin
+ if v5 != 0 then i := flag-ok
+ end
+ if v0 == XOCHIP begin
if v5 == 0 then i := flag-ok
end
x := 59
@@ -487,7 +658,7 @@
sprite x y 3
i := quirks-off
if v5 == 1 then i := quirks-on
- vD := 44
+ vD := 42
vE := 26
drawText
@@ -495,6 +666,152 @@
waitKeyRelease
jump main
+
+: get-frames-per-second-chip8
+ quirks-show-splash-lores
+ i := quirks-values
+ load v6
+ # v0 := 10
+ # v1 := 31
+ # v2 := 0
+ # v3 := 0
+ # v4 := 1
+ # v5 := 180
+ # v6 := 0
+ i := quirks-image
+ delay := v5
+ loop
+ v5 := 30
+ loop
+ sprite v0 v1 1
+ if vF == 0 begin
+ v0 := 54
+ v6 := delay
+ v6 >>= v6
+ v6 >>= v6
+ v0 -= v6
+ end
+ v5 -= 1
+ if v5 != 0 then
+ again
+ v2 += v4
+ v3 += vF
+ vE := delay
+ if vE != 0 then again
+ return
+
+: get-frames-per-second-schip-xochip
+ quirks-show-splash-lores
+ i := quirks-values
+ load v6
+ # v0 := 10
+ # v1 := 31
+ # v2 := 0
+ # v3 := 0
+ # v4 := 1
+ # v5 := 180
+ # v6 := 0
+ v5 >>= v5
+ i := quirks-image
+ delay := v5
+ loop
+ v5 := 30
+ loop
+ sprite v0 v1 1
+ if vF == 0 begin
+ v0 := 32
+ v6 := delay
+ v6 >>= v6
+ v6 >>= v6
+ v0 -= v6
+ end
+ v5 -= 1
+ if v5 != 0 then
+ again
+ v2 += v4
+ v3 += vF
+ vE := delay
+ if vE != 0 then again
+ return
+
+: quirks-show-splash-lores
+ v0 := 8
+ v1 := 0
+ v2 := 15
+ i := splash-0-0
+ loop
+ sprite v0 v1 15
+ i += v2
+ v0 += 8
+ if v0 == 56 begin
+ v0 := 8
+ v1 += 15
+ end
+ if v1 != 30 then
+ again
+ return
+
+: get-frames-per-second-hires
+ v0 := 16
+ v1 := 0
+ v2 := 32
+ i := splash2x-0-0
+ loop
+ sprite v0 v1 0
+ i += v2
+ v0 += 16
+ if v0 == 112 begin
+ v0 := 16
+ v1 += 16
+ end
+ if v1 != 64 then
+ again
+
+ # 11th pixel
+ i := quirks-values
+ load v6
+ # v0 := 10
+ # v1 := 31
+ # v2 := 0
+ # v3 := 0
+ # v4 := 1
+ # v5 := 180
+ # v6 := 0
+ v0 += v0
+ v1 += v1
+ v5 >>= v5
+ i := quirks-line
+ loop
+ sprite v0 v1 2
+ v0 += 8
+ if v0 != 60 then
+ again
+ i := quirks-image
+ loop
+ sprite v0 v1 2
+ v0 += 1
+ if v0 != 64 then
+ again
+ delay := v5
+ loop
+ v5 := 15
+ loop
+ sprite v0 v1 2
+ if vF == 0 begin
+ v0 := 108
+ v6 := delay
+ v6 >>= v6
+ v0 -= v6
+ end
+ v5 -= 1
+ if v5 != 0 then
+ again
+ v2 += v4
+ v3 += vF
+ vE := delay
+ if vE != 0 then again
+ return
+
: scratchpad
0
: scratchpad-plus-1
@@ -680,19 +997,31 @@
: quirks-menu
- 12 11 :pointer quirks-chip8
- 12 16 :pointer quirks-schip
- 12 21 :pointer quirks-xochip
+ 6 11 :pointer quirks-chip8
+ 6 16 :pointer superchip-menu
+ 6 21 :pointer quirks-xochip
: quirks-choose
str "PICK PLATFORM" 0
: quirks-str-chip8
str "1 CHIP-8" 0
: quirks-str-schip
- str "2 SCHIP" 0
+ str "2 SUPER-CHIP" 0
: quirks-str-xochip
str "3 XO-CHIP" 0
+: superchip-target-menu
+ 14 13 :pointer quirks-schip
+ 14 18 :pointer quirks-schip-legacy
+
+: quirks-choose-superchip
+ str "PICK TARGET" 0
+: quirks-str-modern
+ str "1 MODERN" 0
+: quirks-str-legacy
+ str "2 LEGACY" 0
+
+
: quirks-vf
str "VF RESET" 0
: quirks-mem
@@ -710,17 +1039,22 @@
str "ON" 0
: quirks-off
str "OFF" 0
+: quirks-slow
+ str "SLOW" 0
+: quirks-lores
+ str "LRES" 0
+: quirks-hires
+ str "HRES" 0
+: quirks-both
+ str "BOTH" 0
+: quirks-none
+ str "NONE" 0
: quirks-inconsistent-1
- str "E1" 0
+ str "ERR1" 0
: quirks-inconsistent-2
- str "E2" 0
-: quirks-low
- str "LOW" 0
-
-: quirks-values
- 10 31 0 0 1 180 0
-: quirks-image
- 0b10000000
+ str "ERR2" 0
+: quirks-inconsistent-3
+ str "ERR3" 0
: cursor
0b11111110
@@ -730,10 +1064,20 @@
0b11111110
0b11111110
+
+: quirks-values
+ 10 31 0 0 1 180 0
+: quirks-image
+ 0b10000000
+ 0b10000000
+: quirks-line
+ 0b11111111
+ 0b11111111
+
: version-0-0
0x0a 0xae 0xa2 0x42
: version-1-0
- 0x38 0x28 0x28 0xb8
+ 0x10 0x30 0x10 0xb8
: splash-0-0
0x0f 0x02 0x02 0x02 0x02 0x02 0x00 0x00 0x1f 0x3f 0x71 0xe0 0xe5 0xe0 0xe8
@@ -756,10 +1100,83 @@
: 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
+: splash2x-0-0
+ 0x00 0xff 0x00 0xff 0x00 0x0c 0x00 0x0c 0x00 0x0c 0x00 0x0c 0x00 0x0c 0x00 0x0c
+ 0x00 0x0c 0x00 0x0c 0x00 0x0c 0x00 0x0c 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-2-0
+ 0xcc 0x00 0xcc 0x00 0x00 0xf3 0x00 0xf3 0x0c 0xcc 0x0c 0xcc 0x0c 0xc0 0x0c 0xc0
+ 0x0c 0xc0 0x0c 0xc0 0x0c 0xc0 0x0c 0xc0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-4-0
+ 0x00 0x00 0x00 0x00 0x03 0xc3 0x03 0xc3 0xcc 0x33 0xcc 0x33 0xcf 0xf3 0xcf 0xf3
+ 0xcc 0x03 0xcc 0x03 0xc3 0xf3 0xc3 0xf3 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-6-0
+ 0x00 0x03 0x00 0x03 0xf0 0x3f 0xf0 0x3f 0x0c 0xc3 0x0c 0xc3 0x0c 0xc3 0x0c 0xc3
+ 0x0c 0xc3 0x0c 0xc3 0x0c 0x3f 0x0c 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-8-0
+ 0x00 0x00 0x00 0x00 0x30 0xc3 0x30 0xc3 0x30 0xcc 0x30 0xcc 0x30 0xc3 0x30 0xc3
+ 0x30 0xc0 0x30 0xc0 0x0f 0xcf 0x0f 0xcf 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-10-0
+ 0x0f 0x00 0x0f 0x00 0xc3 0x00 0xc3 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0xc0 0x00 0xc0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-0-1
+ 0x03 0xff 0x03 0xff 0x0f 0xff 0x0f 0xff 0x3f 0x03 0x3f 0x03 0xfc 0x00 0xfc 0x00
+ 0xfc 0x33 0xfc 0x33 0xfc 0x00 0xfc 0x00 0xfc 0xc0 0xfc 0xc0 0xfc 0x3f 0xfc 0x3f
+: splash2x-2-1
+ 0x03 0xc0 0x03 0xc0 0xcf 0xc0 0xcf 0xc0 0xcf 0xc0 0xcf 0xc0 0x0f 0xc0 0x0f 0xc0
+ 0x0f 0xc0 0x0f 0xc0 0x0f 0xff 0x0f 0xff 0xcf 0xff 0xcf 0xff 0x0f 0xc3 0x0f 0xc3
+: splash2x-4-1
+ 0x00 0xf0 0x00 0xf0 0x03 0xf3 0x03 0xf3 0x03 0xf3 0x03 0xf3 0x00 0x03 0x00 0x03
+ 0x00 0xf3 0x00 0xf3 0x03 0xf3 0x03 0xf3 0xc3 0xf3 0xc3 0xf3 0xf3 0xf3 0xf3 0xf3
+: splash2x-6-1
+ 0xff 0xc0 0xff 0xc0 0xff 0xf0 0xff 0xf0 0xf0 0xfc 0xf0 0xfc 0xf0 0x3c 0xf0 0x3c
+ 0xf0 0x3c 0xf0 0x3c 0xf0 0x3c 0xf0 0x3c 0xf0 0x3c 0xf0 0x3c 0xf0 0xfc 0xf0 0xfc
+: splash2x-8-1
+ 0x00 0x00 0x00 0x00 0x00 0x03 0x00 0x03 0x00 0x0f 0x00 0x0f 0x00 0x0f 0x00 0x0f
+ 0x00 0x0f 0x00 0x0f 0x00 0x03 0x00 0x03 0xff 0x00 0xff 0x00 0xff 0x03 0xff 0x03
+: splash2x-10-1
+ 0xff 0xfc 0xff 0xfc 0xf0 0x3f 0xf0 0x3f 0xc0 0x0f 0xc0 0x0f 0xc0 0x0f 0xc0 0x0f
+ 0xc0 0x0f 0xc0 0x0f 0xf0 0x3c 0xf0 0x3c 0xff 0xf0 0xff 0xf0 0xf0 0xfc 0xf0 0xfc
+: splash2x-0-2
+ 0xfc 0x00 0xfc 0x00 0xfc 0x00 0xfc 0x00 0xfc 0x00 0xfc 0x00 0xfc 0x00 0xfc 0x00
+ 0x3f 0x03 0x3f 0x03 0x0f 0xff 0x0f 0xff 0x03 0xff 0x03 0xff 0x00 0x00 0x00 0x00
+: splash2x-2-2
+ 0x0f 0xc0 0x0f 0xc0 0x0f 0xc0 0x0f 0xc0 0x0f 0xc0 0x0f 0xc0 0x0f 0xc0 0x0f 0xc0
+ 0xcf 0xc0 0xcf 0xc0 0xcf 0xc0 0xcf 0xc0 0x0f 0xc0 0x0f 0xc0 0x00 0x00 0x00 0x00
+: splash2x-4-2
+ 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3
+ 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0xf3 0x00 0x00 0x00 0x00
+: splash2x-6-2
+ 0xff 0xf0 0xff 0xf0 0xff 0xc0 0xff 0xc0 0xf0 0x00 0xf0 0x00 0xf3 0x30 0xf3 0x30
+ 0xf3 0xf0 0xf3 0xf0 0xf0 0x30 0xf0 0x30 0xf0 0x33 0xf0 0x33 0x00 0x00 0x00 0x00
+: splash2x-8-2
+ 0x00 0x0f 0x00 0x0f 0x00 0x3f 0x00 0x3f 0x00 0x3f 0x00 0x3f 0x0c 0x3f 0x0c 0x3f
+ 0x3c 0x3f 0x3c 0x3f 0x0c 0x0f 0x0c 0x0f 0x3f 0x03 0x3f 0x03 0x00 0x00 0x00 0x00
+: splash2x-10-2
+ 0xc0 0x3f 0xc0 0x3f 0x00 0x0f 0x00 0x0f 0x00 0x0f 0x00 0x0f 0x00 0x0f 0x00 0x0f
+ 0xc0 0x3f 0xc0 0x3f 0xff 0xfc 0xff 0xfc 0xff 0xf0 0xff 0xf0 0x00 0x00 0x00 0x00
+: splash2x-0-3
+ 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x3f 0x00 0x0c 0x00 0x0c 0x00 0x0c 0x00 0x0c
+ 0x00 0x0c 0x00 0x0c 0x00 0x0c 0x00 0x0c 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-2-3
+ 0x00 0x00 0x00 0x00 0x0f 0x03 0x0f 0x03 0x30 0xcc 0x30 0xcc 0x3f 0xc3 0x3f 0xc3
+ 0x30 0x00 0x30 0x00 0x0f 0xcf 0x0f 0xcf 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-4-3
+ 0x00 0x00 0x00 0x00 0xcc 0x00 0xcc 0x00 0x0f 0xc0 0x0f 0xc0 0x0c 0x00 0x0c 0x00
+ 0xcc 0x00 0xcc 0x00 0x03 0xc0 0x03 0xc0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-6-3
+ 0x00 0x00 0x00 0x00 0x0f 0x00 0x0f 0x00 0x30 0x30 0x30 0x30 0x0c 0x30 0x0c 0x30
+ 0x03 0x30 0x03 0x30 0x3c 0x0f 0x3c 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-8-3
+ 0x00 0x00 0x00 0x00 0x0c 0xc0 0x0c 0xc0 0xc0 0xfc 0xc0 0xfc 0xcc 0xc0 0xcc 0xc0
+ 0xcc 0xc0 0xcc 0xc0 0xcc 0x3c 0xcc 0x3c 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+: splash2x-10-3
+ 0x00 0x00 0x00 0x00 0x3c 0x00 0x3c 0x00 0xc3 0x00 0xc3 0x00 0xff 0x00 0xff 0x00
+ 0xc0 0x00 0xc0 0x00 0x3f 0x00 0x3f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+
# Jump quirk targets:
:org 0xE98
diff --git a/bin/5-quirks.ch8 b/bin/5-quirks.ch8
index c4bb488..5206652 100644
Binary files a/bin/5-quirks.ch8 and b/bin/5-quirks.ch8 differ
diff --git a/bin/6-keypad.8o b/bin/6-keypad.8o
index cc70a49..daaea0f 100644
--- a/bin/6-keypad.8o
+++ b/bin/6-keypad.8o
@@ -517,5 +517,5 @@
: version-0-0
0x0a 0xae 0xa2 0x42
: version-1-0
- 0x38 0x28 0x28 0xb8
+ 0x10 0x30 0x10 0xb8
diff --git a/bin/6-keypad.ch8 b/bin/6-keypad.ch8
index db148da..88250bf 100644
Binary files a/bin/6-keypad.ch8 and b/bin/6-keypad.ch8 differ
diff --git a/bin/7-beep.8o b/bin/7-beep.8o
new file mode 100644
index 0000000..87badd4
--- /dev/null
+++ b/bin/7-beep.8o
@@ -0,0 +1,72 @@
+# Beep test
+
+# This is a new test for this test suite, that 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 B button it will give you
+# manual control over the buzzer.
+
+: main
+ i := pattern
+ load v0
+ v2 := 1
+ v3 := v0
+ v4 := 0xB
+ vA := 28
+ vB := 12
+ loop
+ i := pattern
+ i += v2
+ load v1
+ i := speaker
+ sprite vA vB 7
+ buzzer := v0
+ delay := v0
+ wait-for-delay
+ sprite vA vB 7
+ delay := v1
+ wait-for-delay
+ v2 += 2
+ if v2 != v3 then
+ again
+ jump main
+
+: wait-for-delay
+ if v4 key then jump manual-control
+ v0 := delay
+ if v0 != 0 then jump wait-for-delay
+ return
+
+: manual-control
+ v0 := 0
+ v1 := 60
+ v2 := 0xB
+ clear
+ loop
+ i := speaker
+ sprite vA vB 7
+ loop
+ buzzer := v1
+ if v2 key then
+ again
+ sprite vA vB 7
+ loop
+ buzzer := v0
+ if v2 -key then
+ again
+ again
+
+: pattern
+ 19
+ 10 5 10 5 10 20
+ 30 5 30 5 30 20
+ 10 5 10 5 10 60
+
+: speaker
+ 0b00011001
+ 0b00101010
+ 0b11001000
+ 0b10001011
+ 0b11001000
+ 0b00101010
+ 0b00011001
+
diff --git a/bin/7-beep.ch8 b/bin/7-beep.ch8
new file mode 100644
index 0000000..27c205f
Binary files /dev/null and b/bin/7-beep.ch8 differ
diff --git a/bin/8-scrolling.8o b/bin/8-scrolling.8o
new file mode 100644
index 0000000..bcb4aae
--- /dev/null
+++ b/bin/8-scrolling.8o
@@ -0,0 +1,830 @@
+# Scrolling test
+
+# This is a new test for this test suite, that allows you to test if your
+# scrolling opcodes do the right thing. All the arrows should land in their
+# boxes in the direction they point in.
+
+
+
+:stringmode str "$0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ -." {
+ :byte { 4 * VALUE }
+}
+
+:macro text X Y STR {
+ vD := X
+ vE := Y
+ i := STR
+ drawText
+}
+
+:alias x vA
+:alias y vB
+
+: waitKeyRelease
+ v0 := 0
+: -
+ if v0 key then jump -
+ v0 += 1
+ if v0 == 16 then return
+ jump -
+
+# A cute little menu to select a test
+
+# Input:
+# * v0 v1 point to 0xA + menu struct
+# * v2 holds the length (zero-indexed)
+: menu-start
+ :alias cursorX v0
+ :alias cursorY v1
+ :alias numItems v2
+ :alias showing v3
+ :alias temp v4
+ :alias currentItem v5
+ :alias selectedItem v6
+
+ currentItem := 0
+ i := menu-draw-cursor
+ save v1
+ i := menu-choose-load
+ save v1
+ jump menu-draw-cursor
+: menu-move-cursor
+ if showing == 1 then sprite cursorX cursorY 2 # i should still be correct
+ waitKeyRelease
+: menu-draw-cursor
+ 0 0 # i :=