Added stuff.

main
aieque 2020-12-31 19:42:24 +01:00
parent 383396b35c
commit 1734741725
587 changed files with 44799 additions and 0 deletions

1
.gitignore vendored 100644
View File

@ -0,0 +1 @@
/.metadata/

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -0,0 +1 @@
/target/

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>playing-coffee</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,646 @@
[19:39:15.741] Info: Initialized logger
[19:39:15.830] Info: Pushing 0x 2b to the stack.
[19:39:15.831] Info: Pushing 0x 4ce to the stack.
[19:39:15.832] Info: Pushing 0x 39d to the stack.
[19:39:15.832] Info: Pushing 0x 23a to the stack.
[19:39:15.832] Info: Pushing 0x 175 to the stack.
[19:39:15.832] Info: Returning from 0x a8 to 0x 2b
[19:39:15.832] Info: Pushing 0x 2e to the stack.
[19:39:15.833] Info: Pushing 0x 4eb to the stack.
[19:39:15.833] Info: Pushing 0x 3d7 to the stack.
[19:39:15.833] Info: Pushing 0x 2af to the stack.
[19:39:15.833] Info: Pushing 0x 15e to the stack.
[19:39:15.833] Info: Returning from 0x a8 to 0x 2e
[19:39:15.834] Info: Pushing 0x 2b to the stack.
[19:39:15.834] Info: Pushing 0x 4ed to the stack.
[19:39:15.834] Info: Pushing 0x 3db to the stack.
[19:39:15.834] Info: Pushing 0x 2b7 to the stack.
[19:39:15.835] Info: Pushing 0x 16f to the stack.
[19:39:15.835] Info: Returning from 0x a8 to 0x 2b
[19:39:15.835] Info: Pushing 0x 2e to the stack.
[19:39:15.835] Info: Pushing 0x 4de to the stack.
[19:39:15.835] Info: Pushing 0x 3bd to the stack.
[19:39:15.835] Info: Pushing 0x 27b to the stack.
[19:39:15.835] Info: Pushing 0x 1f7 to the stack.
[19:39:15.835] Info: Returning from 0x a8 to 0x 2e
[19:39:15.836] Info: Pushing 0x 2b to the stack.
[19:39:15.836] Info: Pushing 0x 466 to the stack.
[19:39:15.836] Info: Pushing 0x 3cc to the stack.
[19:39:15.836] Info: Pushing 0x 299 to the stack.
[19:39:15.836] Info: Pushing 0x 132 to the stack.
[19:39:15.836] Info: Returning from 0x a8 to 0x 2b
[19:39:15.836] Info: Pushing 0x 2e to the stack.
[19:39:15.836] Info: Pushing 0x 465 to the stack.
[19:39:15.836] Info: Pushing 0x 3ca to the stack.
[19:39:15.837] Info: Pushing 0x 295 to the stack.
[19:39:15.837] Info: Pushing 0x 12b to the stack.
[19:39:15.837] Info: Returning from 0x a8 to 0x 2e
[19:39:15.837] Info: Pushing 0x 2b to the stack.
[19:39:15.837] Info: Pushing 0x 466 to the stack.
[19:39:15.837] Info: Pushing 0x 3cc to the stack.
[19:39:15.837] Info: Pushing 0x 299 to the stack.
[19:39:15.837] Info: Pushing 0x 132 to the stack.
[19:39:15.838] Info: Returning from 0x a8 to 0x 2b
[19:39:15.838] Info: Pushing 0x 2e to the stack.
[19:39:15.838] Info: Pushing 0x 465 to the stack.
[19:39:15.838] Info: Pushing 0x 3ca to the stack.
[19:39:15.838] Info: Pushing 0x 295 to the stack.
[19:39:15.838] Info: Pushing 0x 12b to the stack.
[19:39:15.838] Info: Returning from 0x a8 to 0x 2e
[19:39:15.838] Info: Pushing 0x 2b to the stack.
[19:39:15.839] Info: Pushing 0x 4cc to the stack.
[19:39:15.839] Info: Pushing 0x 399 to the stack.
[19:39:15.839] Info: Pushing 0x 232 to the stack.
[19:39:15.839] Info: Pushing 0x 165 to the stack.
[19:39:15.839] Info: Returning from 0x a8 to 0x 2b
[19:39:15.839] Info: Pushing 0x 2e to the stack.
[19:39:15.839] Info: Pushing 0x 4ca to the stack.
[19:39:15.839] Info: Pushing 0x 395 to the stack.
[19:39:15.840] Info: Pushing 0x 22b to the stack.
[19:39:15.840] Info: Pushing 0x 156 to the stack.
[19:39:15.840] Info: Returning from 0x a8 to 0x 2e
[19:39:15.840] Info: Pushing 0x 2b to the stack.
[19:39:15.840] Info: Pushing 0x 40d to the stack.
[19:39:15.840] Info: Pushing 0x 31a to the stack.
[19:39:15.840] Info: Pushing 0x 234 to the stack.
[19:39:15.840] Info: Pushing 0x 169 to the stack.
[19:39:15.841] Info: Returning from 0x a8 to 0x 2b
[19:39:15.841] Info: Pushing 0x 2e to the stack.
[19:39:15.841] Info: Pushing 0x 4d2 to the stack.
[19:39:15.841] Info: Pushing 0x 3a4 to the stack.
[19:39:15.841] Info: Pushing 0x 248 to the stack.
[19:39:15.841] Info: Pushing 0x 190 to the stack.
[19:39:15.841] Info: Returning from 0x a8 to 0x 2e
[19:39:15.841] Info: Pushing 0x 2b to the stack.
[19:39:15.841] Info: Pushing 0x 400 to the stack.
[19:39:15.842] Info: Pushing 0x 300 to the stack.
[19:39:15.842] Info: Pushing 0x 200 to the stack.
[19:39:15.842] Info: Pushing 0x 100 to the stack.
[19:39:15.842] Info: Returning from 0x a8 to 0x 2b
[19:39:15.842] Info: Pushing 0x 2e to the stack.
[19:39:15.842] Info: Pushing 0x 400 to the stack.
[19:39:17.652] Info: Pushing 0x 300 to the stack.
[19:39:17.652] Info: Pushing 0x 200 to the stack.
[19:39:17.652] Info: Pushing 0x 100 to the stack.
[19:39:17.652] Info: Returning from 0x a8 to 0x 2e
[19:39:17.652] Info: Pushing 0x 2b to the stack.
[19:39:17.652] Info: Pushing 0x 40b to the stack.
[19:39:17.652] Info: Pushing 0x 316 to the stack.
[19:39:17.653] Info: Pushing 0x 22c to the stack.
[19:39:17.653] Info: Pushing 0x 159 to the stack.
[19:39:17.653] Info: Returning from 0x a8 to 0x 2b
[19:39:17.653] Info: Pushing 0x 2e to the stack.
[19:39:17.653] Info: Pushing 0x 4b3 to the stack.
[19:39:17.653] Info: Pushing 0x 366 to the stack.
[19:39:17.653] Info: Pushing 0x 2cc to the stack.
[19:39:17.653] Info: Pushing 0x 198 to the stack.
[19:39:17.653] Info: Returning from 0x a8 to 0x 2e
[19:39:17.654] Info: Pushing 0x 2b to the stack.
[19:39:17.654] Info: Pushing 0x 403 to the stack.
[19:39:17.654] Info: Pushing 0x 306 to the stack.
[19:39:17.654] Info: Pushing 0x 20c to the stack.
[19:39:17.654] Info: Pushing 0x 118 to the stack.
[19:39:17.654] Info: Returning from 0x a8 to 0x 2b
[19:39:17.654] Info: Pushing 0x 2e to the stack.
[19:39:17.654] Info: Pushing 0x 431 to the stack.
[19:39:17.655] Info: Pushing 0x 362 to the stack.
[19:39:17.655] Info: Pushing 0x 2c4 to the stack.
[19:39:17.655] Info: Pushing 0x 188 to the stack.
[19:39:17.655] Info: Returning from 0x a8 to 0x 2e
[19:39:17.655] Info: Pushing 0x 2b to the stack.
[19:39:17.655] Info: Pushing 0x 473 to the stack.
[19:39:17.655] Info: Pushing 0x 3e6 to the stack.
[19:39:17.655] Info: Pushing 0x 2cd to the stack.
[19:39:17.655] Info: Pushing 0x 19a to the stack.
[19:39:17.655] Info: Returning from 0x a8 to 0x 2b
[19:39:17.655] Info: Pushing 0x 2e to the stack.
[19:39:17.656] Info: Pushing 0x 435 to the stack.
[19:39:17.656] Info: Pushing 0x 36a to the stack.
[19:39:17.656] Info: Pushing 0x 2d5 to the stack.
[19:39:17.656] Info: Pushing 0x 1ab to the stack.
[19:39:17.656] Info: Returning from 0x a8 to 0x 2e
[19:39:17.656] Info: Pushing 0x 2b to the stack.
[19:39:17.656] Info: Pushing 0x 400 to the stack.
[19:39:17.657] Info: Pushing 0x 300 to the stack.
[19:39:17.657] Info: Pushing 0x 200 to the stack.
[19:39:17.657] Info: Pushing 0x 100 to the stack.
[19:39:17.657] Info: Returning from 0x a8 to 0x 2b
[19:39:17.658] Info: Pushing 0x 2e to the stack.
[19:39:17.658] Info: Pushing 0x 400 to the stack.
[19:39:17.658] Info: Pushing 0x 300 to the stack.
[19:39:17.658] Info: Pushing 0x 200 to the stack.
[19:39:17.658] Info: Pushing 0x 100 to the stack.
[19:39:17.658] Info: Returning from 0x a8 to 0x 2e
[19:39:17.658] Info: Pushing 0x 2b to the stack.
[19:39:17.658] Info: Pushing 0x 483 to the stack.
[19:39:17.658] Info: Pushing 0x 307 to the stack.
[19:39:17.658] Info: Pushing 0x 20e to the stack.
[19:39:17.660] Info: Pushing 0x 11c to the stack.
[19:39:17.660] Info: Returning from 0x a8 to 0x 2b
[19:39:17.660] Info: Pushing 0x 2e to the stack.
[19:39:17.660] Info: Pushing 0x 439 to the stack.
[19:39:17.667] Info: Pushing 0x 373 to the stack.
[19:39:17.668] Info: Pushing 0x 2e6 to the stack.
[19:39:17.668] Info: Pushing 0x 1cc to the stack.
[19:39:17.668] Info: Returning from 0x a8 to 0x 2e
[19:39:17.668] Info: Pushing 0x 2b to the stack.
[19:39:17.668] Info: Pushing 0x 400 to the stack.
[19:39:17.668] Info: Pushing 0x 300 to the stack.
[19:39:17.668] Info: Pushing 0x 200 to the stack.
[19:39:17.668] Info: Pushing 0x 100 to the stack.
[19:39:17.668] Info: Returning from 0x a8 to 0x 2b
[19:39:17.668] Info: Pushing 0x 2e to the stack.
[19:39:17.668] Info: Pushing 0x 400 to the stack.
[19:39:17.669] Info: Pushing 0x 300 to the stack.
[19:39:17.669] Info: Pushing 0x 200 to the stack.
[19:39:17.669] Info: Pushing 0x 100 to the stack.
[19:39:17.669] Info: Returning from 0x a8 to 0x 2e
[19:39:17.669] Info: Pushing 0x 2b to the stack.
[19:39:17.669] Info: Pushing 0x 40c to the stack.
[19:39:17.669] Info: Pushing 0x 318 to the stack.
[19:39:17.669] Info: Pushing 0x 230 to the stack.
[19:39:17.669] Info: Pushing 0x 161 to the stack.
[19:39:17.669] Info: Returning from 0x a8 to 0x 2b
[19:39:17.670] Info: Pushing 0x 2e to the stack.
[19:39:17.670] Info: Pushing 0x 4c2 to the stack.
[19:39:17.670] Info: Pushing 0x 384 to the stack.
[19:39:17.670] Info: Pushing 0x 208 to the stack.
[19:39:17.670] Info: Pushing 0x 110 to the stack.
[19:39:17.670] Info: Returning from 0x a8 to 0x 2e
[19:39:17.670] Info: Pushing 0x 2b to the stack.
[19:39:17.670] Info: Pushing 0x 400 to the stack.
[19:39:17.670] Info: Pushing 0x 300 to the stack.
[19:39:17.670] Info: Pushing 0x 200 to the stack.
[19:39:17.670] Info: Pushing 0x 100 to the stack.
[19:39:17.671] Info: Returning from 0x a8 to 0x 2b
[19:39:17.671] Info: Pushing 0x 2e to the stack.
[19:39:17.671] Info: Pushing 0x 400 to the stack.
[19:39:17.671] Info: Pushing 0x 300 to the stack.
[19:39:17.671] Info: Pushing 0x 200 to the stack.
[19:39:17.671] Info: Pushing 0x 100 to the stack.
[19:39:17.671] Info: Returning from 0x a8 to 0x 2e
[19:39:17.671] Info: Pushing 0x 2b to the stack.
[19:39:17.671] Info: Pushing 0x 40d to the stack.
[19:39:17.671] Info: Pushing 0x 31a to the stack.
[19:39:17.671] Info: Pushing 0x 234 to the stack.
[19:39:17.671] Info: Pushing 0x 169 to the stack.
[19:39:17.671] Info: Returning from 0x a8 to 0x 2b
[19:39:17.671] Info: Pushing 0x 2e to the stack.
[19:39:17.672] Info: Pushing 0x 4d2 to the stack.
[19:39:17.672] Info: Pushing 0x 3a4 to the stack.
[19:39:17.672] Info: Pushing 0x 248 to the stack.
[19:39:17.672] Info: Pushing 0x 190 to the stack.
[19:39:17.672] Info: Returning from 0x a8 to 0x 2e
[19:39:17.672] Info: Pushing 0x 2b to the stack.
[19:39:17.672] Info: Pushing 0x 400 to the stack.
[19:39:17.672] Info: Pushing 0x 300 to the stack.
[19:39:17.672] Info: Pushing 0x 200 to the stack.
[19:39:17.672] Info: Pushing 0x 100 to the stack.
[19:39:17.672] Info: Returning from 0x a8 to 0x 2b
[19:39:17.672] Info: Pushing 0x 2e to the stack.
[19:39:17.673] Info: Pushing 0x 400 to the stack.
[19:39:17.673] Info: Pushing 0x 300 to the stack.
[19:39:17.673] Info: Pushing 0x 200 to the stack.
[19:39:17.673] Info: Pushing 0x 100 to the stack.
[19:39:17.673] Info: Returning from 0x a8 to 0x 2e
[19:39:17.673] Info: Pushing 0x 2b to the stack.
[19:39:17.673] Info: Pushing 0x 408 to the stack.
[19:39:17.673] Info: Pushing 0x 310 to the stack.
[19:39:17.673] Info: Pushing 0x 220 to the stack.
[19:39:17.673] Info: Pushing 0x 141 to the stack.
[19:39:17.673] Info: Returning from 0x a8 to 0x 2b
[19:39:17.673] Info: Pushing 0x 2e to the stack.
[19:39:17.673] Info: Pushing 0x 482 to the stack.
[19:39:17.673] Info: Pushing 0x 304 to the stack.
[19:39:17.674] Info: Pushing 0x 208 to the stack.
[19:39:17.674] Info: Pushing 0x 110 to the stack.
[19:39:17.674] Info: Returning from 0x a8 to 0x 2e
[19:39:17.674] Info: Pushing 0x 2b to the stack.
[19:39:17.674] Info: Pushing 0x 411 to the stack.
[19:39:17.674] Info: Pushing 0x 322 to the stack.
[19:39:17.674] Info: Pushing 0x 244 to the stack.
[19:39:17.674] Info: Pushing 0x 188 to the stack.
[19:39:17.674] Info: Returning from 0x a8 to 0x 2b
[19:39:17.674] Info: Pushing 0x 2e to the stack.
[19:39:17.674] Info: Pushing 0x 410 to the stack.
[19:39:17.675] Info: Pushing 0x 320 to the stack.
[19:39:17.675] Info: Pushing 0x 240 to the stack.
[19:39:17.675] Info: Pushing 0x 180 to the stack.
[19:39:17.675] Info: Returning from 0x a8 to 0x 2e
[19:39:17.675] Info: Pushing 0x 2b to the stack.
[19:39:17.675] Info: Pushing 0x 41f to the stack.
[19:39:17.675] Info: Pushing 0x 33e to the stack.
[19:39:17.675] Info: Pushing 0x 27c to the stack.
[19:39:17.675] Info: Pushing 0x 1f9 to the stack.
[19:39:17.675] Info: Returning from 0x a8 to 0x 2b
[19:39:17.675] Info: Pushing 0x 2e to the stack.
[19:39:17.675] Info: Pushing 0x 4f3 to the stack.
[19:39:17.675] Info: Pushing 0x 3e6 to the stack.
[19:39:17.676] Info: Pushing 0x 2cc to the stack.
[19:39:17.676] Info: Pushing 0x 198 to the stack.
[19:39:17.676] Info: Returning from 0x a8 to 0x 2e
[19:39:17.676] Info: Pushing 0x 2b to the stack.
[19:39:17.676] Info: Pushing 0x 488 to the stack.
[19:39:17.676] Info: Pushing 0x 311 to the stack.
[19:39:17.676] Info: Pushing 0x 222 to the stack.
[19:39:17.676] Info: Pushing 0x 145 to the stack.
[19:39:17.676] Info: Returning from 0x a8 to 0x 2b
[19:39:17.676] Info: Pushing 0x 2e to the stack.
[19:39:17.676] Info: Pushing 0x 48a to the stack.
[19:39:17.676] Info: Pushing 0x 315 to the stack.
[19:39:17.676] Info: Pushing 0x 22a to the stack.
[19:39:17.677] Info: Pushing 0x 154 to the stack.
[19:39:17.677] Info: Returning from 0x a8 to 0x 2e
[19:39:17.677] Info: Pushing 0x 2b to the stack.
[19:39:17.677] Info: Pushing 0x 489 to the stack.
[19:39:17.677] Info: Pushing 0x 313 to the stack.
[19:39:17.677] Info: Pushing 0x 226 to the stack.
[19:39:17.677] Info: Pushing 0x 14d to the stack.
[19:39:17.677] Info: Returning from 0x a8 to 0x 2b
[19:39:17.677] Info: Pushing 0x 2e to the stack.
[19:39:17.677] Info: Pushing 0x 49a to the stack.
[19:39:17.678] Info: Pushing 0x 335 to the stack.
[19:39:17.678] Info: Pushing 0x 26a to the stack.
[19:39:17.678] Info: Pushing 0x 1d4 to the stack.
[19:39:17.678] Info: Returning from 0x a8 to 0x 2e
[19:39:17.678] Info: Pushing 0x 2b to the stack.
[19:39:17.678] Info: Pushing 0x 400 to the stack.
[19:39:17.678] Info: Pushing 0x 300 to the stack.
[19:39:17.678] Info: Pushing 0x 200 to the stack.
[19:39:17.678] Info: Pushing 0x 100 to the stack.
[19:39:17.678] Info: Returning from 0x a8 to 0x 2b
[19:39:17.678] Info: Pushing 0x 2e to the stack.
[19:39:17.678] Info: Pushing 0x 400 to the stack.
[19:39:17.678] Info: Pushing 0x 300 to the stack.
[19:39:17.678] Info: Pushing 0x 200 to the stack.
[19:39:17.680] Info: Pushing 0x 100 to the stack.
[19:39:17.680] Info: Returning from 0x a8 to 0x 2e
[19:39:17.680] Info: Pushing 0x 2b to the stack.
[19:39:17.680] Info: Pushing 0x 40e to the stack.
[19:39:17.680] Info: Pushing 0x 31c to the stack.
[19:39:17.680] Info: Pushing 0x 238 to the stack.
[19:39:17.680] Info: Pushing 0x 171 to the stack.
[19:39:17.680] Info: Returning from 0x a8 to 0x 2b
[19:39:17.680] Info: Pushing 0x 2e to the stack.
[19:39:17.681] Info: Pushing 0x 4e3 to the stack.
[19:39:17.681] Info: Pushing 0x 3c6 to the stack.
[19:39:17.681] Info: Pushing 0x 28c to the stack.
[19:39:17.681] Info: Pushing 0x 118 to the stack.
[19:39:17.681] Info: Returning from 0x a8 to 0x 2e
[19:39:17.681] Info: Pushing 0x 2b to the stack.
[19:39:17.681] Info: Pushing 0x 4dc to the stack.
[19:39:17.681] Info: Pushing 0x 3b9 to the stack.
[19:39:17.681] Info: Pushing 0x 272 to the stack.
[19:39:17.682] Info: Pushing 0x 1e5 to the stack.
[19:39:17.682] Info: Returning from 0x a8 to 0x 2b
[19:39:17.682] Info: Pushing 0x 2e to the stack.
[19:39:17.682] Info: Pushing 0x 4ca to the stack.
[19:39:17.682] Info: Pushing 0x 395 to the stack.
[19:39:17.682] Info: Pushing 0x 22b to the stack.
[19:39:17.682] Info: Pushing 0x 156 to the stack.
[19:39:17.682] Info: Returning from 0x a8 to 0x 2e
[19:39:17.682] Info: Pushing 0x 2b to the stack.
[19:39:17.682] Info: Pushing 0x 4cc to the stack.
[19:39:17.682] Info: Pushing 0x 399 to the stack.
[19:39:17.682] Info: Pushing 0x 232 to the stack.
[19:39:17.682] Info: Pushing 0x 165 to the stack.
[19:39:17.683] Info: Returning from 0x a8 to 0x 2b
[19:39:17.683] Info: Pushing 0x 2e to the stack.
[19:39:17.683] Info: Pushing 0x 4ca to the stack.
[19:39:17.683] Info: Pushing 0x 395 to the stack.
[19:39:17.683] Info: Pushing 0x 22b to the stack.
[19:39:17.683] Info: Pushing 0x 156 to the stack.
[19:39:17.683] Info: Returning from 0x a8 to 0x 2e
[19:39:17.683] Info: Pushing 0x 2b to the stack.
[19:39:17.683] Info: Pushing 0x 46e to the stack.
[19:39:17.683] Info: Pushing 0x 3dc to the stack.
[19:39:17.683] Info: Pushing 0x 2b9 to the stack.
[19:39:17.683] Info: Pushing 0x 173 to the stack.
[19:39:17.683] Info: Returning from 0x a8 to 0x 2b
[19:39:17.683] Info: Pushing 0x 2e to the stack.
[19:39:17.684] Info: Pushing 0x 4e7 to the stack.
[19:39:17.684] Info: Pushing 0x 3ce to the stack.
[19:39:17.684] Info: Pushing 0x 29d to the stack.
[19:39:17.684] Info: Pushing 0x 13b to the stack.
[19:39:17.684] Info: Returning from 0x a8 to 0x 2e
[19:39:17.684] Info: Pushing 0x 2b to the stack.
[19:39:17.684] Info: Pushing 0x 4e6 to the stack.
[19:39:17.684] Info: Pushing 0x 3cd to the stack.
[19:39:17.684] Info: Pushing 0x 29b to the stack.
[19:39:17.684] Info: Pushing 0x 136 to the stack.
[19:39:17.684] Info: Returning from 0x a8 to 0x 2b
[19:39:17.684] Info: Pushing 0x 2e to the stack.
[19:39:17.684] Info: Pushing 0x 46d to the stack.
[19:39:17.684] Info: Pushing 0x 3db to the stack.
[19:39:17.685] Info: Pushing 0x 2b7 to the stack.
[19:39:17.685] Info: Pushing 0x 16f to the stack.
[19:39:17.685] Info: Returning from 0x a8 to 0x 2e
[19:39:17.685] Info: Pushing 0x 2b to the stack.
[19:39:17.685] Info: Pushing 0x 4dd to the stack.
[19:39:17.685] Info: Pushing 0x 3bb to the stack.
[19:39:17.685] Info: Pushing 0x 276 to the stack.
[19:39:17.685] Info: Pushing 0x 1ed to the stack.
[19:39:17.686] Info: Returning from 0x a8 to 0x 2b
[19:39:17.686] Info: Pushing 0x 2e to the stack.
[19:39:17.686] Info: Pushing 0x 4da to the stack.
[19:39:17.686] Info: Pushing 0x 3b5 to the stack.
[19:39:17.686] Info: Pushing 0x 26b to the stack.
[19:39:17.686] Info: Pushing 0x 1d6 to the stack.
[19:39:17.686] Info: Returning from 0x a8 to 0x 2e
[19:39:17.686] Info: Pushing 0x 2b to the stack.
[19:39:17.686] Info: Pushing 0x 4dd to the stack.
[19:39:17.686] Info: Pushing 0x 3bb to the stack.
[19:39:17.686] Info: Pushing 0x 276 to the stack.
[19:39:17.686] Info: Pushing 0x 1ed to the stack.
[19:39:17.686] Info: Returning from 0x a8 to 0x 2b
[19:39:17.686] Info: Pushing 0x 2e to the stack.
[19:39:17.688] Info: Pushing 0x 4da to the stack.
[19:39:17.688] Info: Pushing 0x 3b5 to the stack.
[19:39:17.688] Info: Pushing 0x 26b to the stack.
[19:39:17.688] Info: Pushing 0x 1d6 to the stack.
[19:39:17.689] Info: Returning from 0x a8 to 0x 2e
[19:39:17.689] Info: Pushing 0x 2b to the stack.
[19:39:17.689] Info: Pushing 0x 4d9 to the stack.
[19:39:17.689] Info: Pushing 0x 3b3 to the stack.
[19:39:17.689] Info: Pushing 0x 266 to the stack.
[19:39:17.689] Info: Pushing 0x 1cd to the stack.
[19:39:17.689] Info: Returning from 0x a8 to 0x 2b
[19:39:17.689] Info: Pushing 0x 2e to the stack.
[19:39:17.689] Info: Pushing 0x 49a to the stack.
[19:39:17.689] Info: Pushing 0x 335 to the stack.
[19:39:17.689] Info: Pushing 0x 26b to the stack.
[19:39:17.689] Info: Pushing 0x 1d6 to the stack.
[19:39:17.689] Info: Returning from 0x a8 to 0x 2e
[19:39:17.689] Info: Pushing 0x 2b to the stack.
[19:39:17.689] Info: Pushing 0x 499 to the stack.
[19:39:17.689] Info: Pushing 0x 333 to the stack.
[19:39:17.689] Info: Pushing 0x 266 to the stack.
[19:39:17.690] Info: Pushing 0x 1cd to the stack.
[19:39:17.690] Info: Returning from 0x a8 to 0x 2b
[19:39:17.690] Info: Pushing 0x 2e to the stack.
[19:39:17.690] Info: Pushing 0x 49a to the stack.
[19:39:17.690] Info: Pushing 0x 335 to the stack.
[19:39:17.690] Info: Pushing 0x 26a to the stack.
[19:39:17.690] Info: Pushing 0x 1d4 to the stack.
[19:39:17.690] Info: Returning from 0x a8 to 0x 2e
[19:39:17.690] Info: Pushing 0x 2b to the stack.
[19:39:17.690] Info: Pushing 0x 4bb to the stack.
[19:39:17.690] Info: Pushing 0x 377 to the stack.
[19:39:17.690] Info: Pushing 0x 2ef to the stack.
[19:39:17.690] Info: Pushing 0x 1df to the stack.
[19:39:17.690] Info: Returning from 0x a8 to 0x 2b
[19:39:17.690] Info: Pushing 0x 2e to the stack.
[19:39:17.690] Info: Pushing 0x 4bf to the stack.
[19:39:17.691] Info: Pushing 0x 37f to the stack.
[19:39:17.691] Info: Pushing 0x 2fe to the stack.
[19:39:17.691] Info: Pushing 0x 1fd to the stack.
[19:39:17.691] Info: Returning from 0x a8 to 0x 2e
[19:39:17.691] Info: Pushing 0x 2b to the stack.
[19:39:17.691] Info: Pushing 0x 4bb to the stack.
[19:39:17.691] Info: Pushing 0x 377 to the stack.
[19:39:17.691] Info: Pushing 0x 2ef to the stack.
[19:39:17.691] Info: Pushing 0x 1df to the stack.
[19:39:17.691] Info: Returning from 0x a8 to 0x 2b
[19:39:17.691] Info: Pushing 0x 2e to the stack.
[19:39:17.691] Info: Pushing 0x 4bf to the stack.
[19:39:17.691] Info: Pushing 0x 37f to the stack.
[19:39:17.691] Info: Pushing 0x 2fe to the stack.
[19:39:17.691] Info: Pushing 0x 1fd to the stack.
[19:39:17.691] Info: Returning from 0x a8 to 0x 2e
[19:39:17.691] Info: Pushing 0x 2b to the stack.
[19:39:17.691] Info: Pushing 0x 467 to the stack.
[19:39:17.692] Info: Pushing 0x 3ce to the stack.
[19:39:17.692] Info: Pushing 0x 29d to the stack.
[19:39:17.694] Info: Pushing 0x 13a to the stack.
[19:39:17.694] Info: Returning from 0x a8 to 0x 2b
[19:39:17.694] Info: Pushing 0x 2e to the stack.
[19:39:17.694] Info: Pushing 0x 475 to the stack.
[19:39:17.694] Info: Pushing 0x 3ea to the stack.
[19:39:17.694] Info: Pushing 0x 2d5 to the stack.
[19:39:17.694] Info: Pushing 0x 1ab to the stack.
[19:39:17.694] Info: Returning from 0x a8 to 0x 2e
[19:39:17.694] Info: Pushing 0x 2b to the stack.
[19:39:17.694] Info: Pushing 0x 463 to the stack.
[19:39:17.694] Info: Pushing 0x 3c6 to the stack.
[19:39:17.694] Info: Pushing 0x 28d to the stack.
[19:39:17.694] Info: Pushing 0x 11a to the stack.
[19:39:17.694] Info: Returning from 0x a8 to 0x 2b
[19:39:17.694] Info: Pushing 0x 2e to the stack.
[19:39:17.694] Info: Pushing 0x 435 to the stack.
[19:39:17.694] Info: Pushing 0x 36a to the stack.
[19:39:17.694] Info: Pushing 0x 2d5 to the stack.
[19:39:17.695] Info: Pushing 0x 1ab to the stack.
[19:39:17.695] Info: Returning from 0x a8 to 0x 2e
[19:39:17.695] Info: Pushing 0x 2b to the stack.
[19:39:17.695] Info: Pushing 0x 46e to the stack.
[19:39:17.695] Info: Pushing 0x 3dc to the stack.
[19:39:17.695] Info: Pushing 0x 2b9 to the stack.
[19:39:17.695] Info: Pushing 0x 173 to the stack.
[19:39:17.695] Info: Returning from 0x a8 to 0x 2b
[19:39:17.695] Info: Pushing 0x 2e to the stack.
[19:39:17.695] Info: Pushing 0x 4e7 to the stack.
[19:39:17.695] Info: Pushing 0x 3ce to the stack.
[19:39:17.695] Info: Pushing 0x 29d to the stack.
[19:39:17.695] Info: Pushing 0x 13b to the stack.
[19:39:17.695] Info: Returning from 0x a8 to 0x 2e
[19:39:17.696] Info: Pushing 0x 2b to the stack.
[19:39:17.696] Info: Pushing 0x 40e to the stack.
[19:39:17.696] Info: Pushing 0x 31c to the stack.
[19:39:17.696] Info: Pushing 0x 238 to the stack.
[19:39:17.696] Info: Pushing 0x 171 to the stack.
[19:39:17.696] Info: Returning from 0x a8 to 0x 2b
[19:39:17.696] Info: Pushing 0x 2e to the stack.
[19:39:17.696] Info: Pushing 0x 4e3 to the stack.
[19:39:17.696] Info: Pushing 0x 3c6 to the stack.
[19:39:17.696] Info: Pushing 0x 28c to the stack.
[19:39:17.696] Info: Pushing 0x 118 to the stack.
[19:39:17.696] Info: Returning from 0x a8 to 0x 2e
[19:39:17.696] Info: Pushing 0x 2b to the stack.
[19:39:17.696] Info: Pushing 0x 4ec to the stack.
[19:39:17.696] Info: Pushing 0x 3d9 to the stack.
[19:39:17.696] Info: Pushing 0x 2b3 to the stack.
[19:39:17.696] Info: Pushing 0x 167 to the stack.
[19:39:17.696] Info: Returning from 0x a8 to 0x 2b
[19:39:17.696] Info: Pushing 0x 2e to the stack.
[19:39:17.696] Info: Pushing 0x 4ce to the stack.
[19:39:17.697] Info: Pushing 0x 39d to the stack.
[19:39:17.697] Info: Pushing 0x 23b to the stack.
[19:39:17.697] Info: Pushing 0x 177 to the stack.
[19:39:17.697] Info: Returning from 0x a8 to 0x 2e
[19:39:17.697] Info: Pushing 0x 2b to the stack.
[19:39:17.698] Info: Pushing 0x 4cc to the stack.
[19:39:17.698] Info: Pushing 0x 399 to the stack.
[19:39:17.698] Info: Pushing 0x 232 to the stack.
[19:39:17.698] Info: Pushing 0x 165 to the stack.
[19:39:17.698] Info: Returning from 0x a8 to 0x 2b
[19:39:17.698] Info: Pushing 0x 2e to the stack.
[19:39:17.698] Info: Pushing 0x 4ca to the stack.
[19:39:17.698] Info: Pushing 0x 395 to the stack.
[19:39:17.698] Info: Pushing 0x 22b to the stack.
[19:39:17.698] Info: Pushing 0x 156 to the stack.
[19:39:17.699] Info: Returning from 0x a8 to 0x 2e
[19:39:17.699] Info: Pushing 0x 2b to the stack.
[19:39:17.699] Info: Pushing 0x 4dd to the stack.
[19:39:17.699] Info: Pushing 0x 3bb to the stack.
[19:39:17.699] Info: Pushing 0x 276 to the stack.
[19:39:17.699] Info: Pushing 0x 1ed to the stack.
[19:39:17.699] Info: Returning from 0x a8 to 0x 2b
[19:39:17.699] Info: Pushing 0x 2e to the stack.
[19:39:17.699] Info: Pushing 0x 4da to the stack.
[19:39:17.699] Info: Pushing 0x 3b5 to the stack.
[19:39:17.699] Info: Pushing 0x 26b to the stack.
[19:39:17.699] Info: Pushing 0x 1d6 to the stack.
[19:39:17.699] Info: Returning from 0x a8 to 0x 2e
[19:39:17.699] Info: Pushing 0x 2b to the stack.
[19:39:17.699] Info: Pushing 0x 4dc to the stack.
[19:39:17.699] Info: Pushing 0x 3b9 to the stack.
[19:39:17.699] Info: Pushing 0x 272 to the stack.
[19:39:17.700] Info: Pushing 0x 1e5 to the stack.
[19:39:17.700] Info: Returning from 0x a8 to 0x 2b
[19:39:17.700] Info: Pushing 0x 2e to the stack.
[19:39:17.700] Info: Pushing 0x 4ca to the stack.
[19:39:17.700] Info: Pushing 0x 395 to the stack.
[19:39:17.700] Info: Pushing 0x 22b to the stack.
[19:39:17.700] Info: Pushing 0x 156 to the stack.
[19:39:17.700] Info: Returning from 0x a8 to 0x 2e
[19:39:17.700] Info: Pushing 0x 2b to the stack.
[19:39:17.700] Info: Pushing 0x 499 to the stack.
[19:39:17.700] Info: Pushing 0x 333 to the stack.
[19:39:17.700] Info: Pushing 0x 266 to the stack.
[19:39:17.700] Info: Pushing 0x 1cd to the stack.
[19:39:17.700] Info: Returning from 0x a8 to 0x 2b
[19:39:17.700] Info: Pushing 0x 2e to the stack.
[19:39:17.700] Info: Pushing 0x 49a to the stack.
[19:39:17.700] Info: Pushing 0x 335 to the stack.
[19:39:17.700] Info: Pushing 0x 26a to the stack.
[19:39:17.701] Info: Pushing 0x 1d4 to the stack.
[19:39:17.701] Info: Returning from 0x a8 to 0x 2e
[19:39:17.702] Info: Pushing 0x 2b to the stack.
[19:39:17.702] Info: Pushing 0x 49f to the stack.
[19:39:17.702] Info: Pushing 0x 33f to the stack.
[19:39:17.702] Info: Pushing 0x 27e to the stack.
[19:39:17.702] Info: Pushing 0x 1fd to the stack.
[19:39:17.702] Info: Returning from 0x a8 to 0x 2b
[19:39:17.702] Info: Pushing 0x 2e to the stack.
[19:39:17.702] Info: Pushing 0x 4fb to the stack.
[19:39:17.702] Info: Pushing 0x 3f7 to the stack.
[19:39:17.702] Info: Pushing 0x 2ee to the stack.
[19:39:17.702] Info: Pushing 0x 1dc to the stack.
[19:39:17.702] Info: Returning from 0x a8 to 0x 2e
[19:39:17.702] Info: Pushing 0x 2b to the stack.
[19:39:17.702] Info: Pushing 0x 4bb to the stack.
[19:39:17.702] Info: Pushing 0x 377 to the stack.
[19:39:17.702] Info: Pushing 0x 2ef to the stack.
[19:39:17.703] Info: Pushing 0x 1df to the stack.
[19:39:17.703] Info: Returning from 0x a8 to 0x 2b
[19:39:17.703] Info: Pushing 0x 2e to the stack.
[19:39:17.703] Info: Pushing 0x 4bf to the stack.
[19:39:17.703] Info: Pushing 0x 37f to the stack.
[19:39:17.703] Info: Pushing 0x 2fe to the stack.
[19:39:17.703] Info: Pushing 0x 1fd to the stack.
[19:39:17.703] Info: Returning from 0x a8 to 0x 2e
[19:39:17.703] Info: Pushing 0x 2b to the stack.
[19:39:17.703] Info: Pushing 0x 4b9 to the stack.
[19:39:17.703] Info: Pushing 0x 373 to the stack.
[19:39:17.703] Info: Pushing 0x 2e7 to the stack.
[19:39:17.703] Info: Pushing 0x 1cf to the stack.
[19:39:17.703] Info: Returning from 0x a8 to 0x 2b
[19:39:17.703] Info: Pushing 0x 2e to the stack.
[19:39:17.703] Info: Pushing 0x 49e to the stack.
[19:39:17.703] Info: Pushing 0x 33d to the stack.
[19:39:17.703] Info: Pushing 0x 27a to the stack.
[19:39:17.705] Info: Pushing 0x 1f5 to the stack.
[19:39:17.705] Info: Returning from 0x a8 to 0x 2e
[19:39:17.705] Info: Pushing 0x 2b to the stack.
[19:39:17.705] Info: Pushing 0x 433 to the stack.
[19:39:17.705] Info: Pushing 0x 366 to the stack.
[19:39:17.705] Info: Pushing 0x 2cd to the stack.
[19:39:17.705] Info: Pushing 0x 19a to the stack.
[19:39:17.705] Info: Returning from 0x a8 to 0x 2b
[19:39:17.705] Info: Pushing 0x 2e to the stack.
[19:39:17.705] Info: Pushing 0x 435 to the stack.
[19:39:17.705] Info: Pushing 0x 36a to the stack.
[19:39:17.705] Info: Pushing 0x 2d4 to the stack.
[19:39:17.705] Info: Pushing 0x 1a9 to the stack.
[19:39:17.705] Info: Returning from 0x a8 to 0x 2e
[19:39:17.705] Info: Pushing 0x 2b to the stack.
[19:39:17.705] Info: Pushing 0x 43e to the stack.
[19:39:17.705] Info: Pushing 0x 37c to the stack.
[19:39:17.705] Info: Pushing 0x 2f9 to the stack.
[19:39:17.705] Info: Pushing 0x 1f3 to the stack.
[19:39:17.705] Info: Returning from 0x a8 to 0x 2b
[19:39:17.705] Info: Pushing 0x 2e to the stack.
[19:39:17.705] Info: Pushing 0x 4e7 to the stack.
[19:39:17.706] Info: Pushing 0x 3ce to the stack.
[19:39:17.706] Info: Pushing 0x 29c to the stack.
[19:39:17.706] Info: Pushing 0x 139 to the stack.
[19:39:17.706] Info: Returning from 0x a8 to 0x 2e
[19:39:22.038] Info: Pushing 0x 153 to the stack.
[19:39:22.042] Info: Returning from 0x2c20 to 0x 153
[19:39:22.042] Info: Pushing 0x 159 to the stack.
[19:39:22.042] Info: Returning from 0x2b94 to 0x 159
[19:39:22.042] Info: Pushing 0x 15e to the stack.
[19:39:22.056] Info: Returning from 0x2c47 to 0x 15e
[19:39:22.136] Info: Pushing 0x 19a to the stack.
[19:39:22.136] Info: Returning from 0x71de to 0x 19a
[19:39:22.136] Info: Pushing 0x 1c5 to the stack.
[19:39:22.136] Info: Pushing 0x1f8c to the stack.
[19:39:22.136] Info: Pushing 0x 80 to the stack.
[19:39:22.136] Info: Pushing 0x ff to the stack.
[19:39:22.136] Info: Pushing 0xf810 to the stack.
[19:39:22.136] Info: Pushing 0xc000 to the stack.
[19:39:22.139] Info: Returning from 0x2c38 to 0x1f8c
[19:39:22.139] Info: Returning from 0x1f8d to 0x 1c5
[19:39:22.139] Info: Pushing 0x 1c8 to the stack.
[19:39:22.139] Info: Pushing 0x 203 to the stack.
[19:39:22.139] Info: Pushing 0x 80 to the stack.
[19:39:22.139] Info: Pushing 0x 168 to the stack.
[19:39:22.139] Info: Pushing 0xf810 to the stack.
[19:39:22.140] Info: Pushing 0xc100 to the stack.
[19:39:22.144] Info: Returning from 0x2c38 to 0x 203
[19:39:22.144] Info: Pushing 0x 206 to the stack.
[19:39:22.144] Info: Pushing 0x 168 to the stack.
[19:39:22.144] Info: Pushing 0x1b92 to the stack.
[19:39:22.144] Info: Pushing 0x 168 to the stack.
[19:39:22.144] Info: Pushing 0xf810 to the stack.
[19:39:22.144] Info: Pushing 0xc100 to the stack.
[19:39:22.144] Info: Pushing 0x 0 to the stack.
[19:39:22.144] Info: Pushing 0x3eff to the stack.
[19:39:22.144] Info: Returning from 0x27bd to 0x1b92
[19:39:22.144] Info: Pushing 0xffa0 to the stack.
[19:39:22.144] Info: Pushing 0x1b96 to the stack.
[19:39:22.144] Info: Pushing 0xc100 to the stack.
[19:39:22.144] Info: Pushing 0x 168 to the stack.
[19:39:22.144] Info: Pushing 0x1bae to the stack.
[19:39:22.144] Info: Pushing 0x 168 to the stack.
[19:39:22.144] Info: Pushing 0xf810 to the stack.
[19:39:22.145] Info: Returning from 0x1f4d to 0x1bae
[19:39:22.145] Info: Returning from 0x1bc4 to 0x1b96
[19:39:22.145] Info: Pushing 0x1b99 to the stack.
[19:39:22.145] Info: Returning from 0x1f7f to 0x1b99
[19:39:22.145] Warning: Attempting to write to ROM at address: 0x 0.
[19:39:22.145] Info: Pushing 0x 167 to the stack.
[19:39:22.145] Info: Pushing 0x1b92 to the stack.
[19:39:22.145] Info: Pushing 0x 167 to the stack.
[19:39:22.145] Info: Pushing 0x 0 to the stack.
[19:39:22.145] Info: Pushing 0xc101 to the stack.
[19:39:22.145] Info: Pushing 0x f to the stack.
[19:39:22.145] Info: Pushing 0x3eff to the stack.
[19:39:22.145] Info: Returning from 0x27bd to 0x1b92
[19:39:22.145] Info: Pushing 0xffa0 to the stack.
[19:39:22.145] Info: Pushing 0x1b96 to the stack.
[19:39:22.145] Info: Pushing 0xc101 to the stack.
[19:39:22.145] Info: Pushing 0x 167 to the stack.
[19:39:22.145] Info: Pushing 0x1bae to the stack.
[19:39:22.145] Info: Pushing 0x 167 to the stack.
[19:39:22.145] Info: Pushing 0x 0 to the stack.
[19:39:22.146] Info: Returning from 0x1f4d to 0x1bae
[19:39:22.147] Info: Returning from 0x1bc4 to 0x1b96
[19:39:22.147] Info: Pushing 0x1b99 to the stack.
[19:39:22.147] Info: Returning from 0x1f7f to 0xffa0
[19:39:22.147] Info: Pushing 0xfbc3 to the stack.
[19:39:22.148] Info: Returning from 0xff8a to 0x 0
[19:39:22.148] Info: Pushing 0xfbc3 to the stack.
[19:39:22.152] Info: Returning from 0xff47 to 0x 0
[19:39:22.152] Info: Pushing 0xfbc3 to the stack.
[19:39:22.152] Error: Unimplemented opcode 0xfd at 0xfbc4!

View File

@ -0,0 +1,15 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sixtenhugosson</groupId>
<artifactId>playing-coffee</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>playing-coffee</name>
<description>A GameBoy emulator written in Java.</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,86 @@
Game Boy Sound Hardware Tests
-----------------------------
These tests verify aspects of the sound hardware that the CPU can
observe. The ROMs and GBSs are either for DMG or CGB hardware, as there
are several differences.
Multi-ROM
---------
In the main directory is a single ROM/GBS which runs all the tests. It
prints a test's number, runs the test, then "ok" if it passes, otherwise
a failure code. Once all tests have completed it either reports that all
tests passed, or reports the number of the first failed test as the
result code (1 = first). Finally, it makes several beeps. If a test
fails, it can be run on its own by finding the corresponding ROM/GBS in
the singles directories.
Ths compact format on screen is to avoid having the results scroll off
the top, so the test can be started and allowed to run without having to
constantly monitor the display.
Failure information
-------------------
For more information about a failure code or information printed, see
the test's source code in source/. To find failure code N, search for
"set_test N", which will usually be before the subtest which failed.
Flashes, clicks, other glitches
-------------------------------
Some tests might need to turn the screen off and on, or cause slight
audio clicks. This does not indicate failure, and should be ignored.
Only the test result reported at the end is important, unless stated
otherwise.
LCD support
-----------
Tests generally print information on screen. The tests will work fine if
run on an emulator with NO LCD support, or as an GBS which has no
inherent screen; in particular, the VBL wait routine has a timeout in
case LY doesn't reflect the current LCD line. The text printing will
also work if the LCD doesn't support scrolling.
Output to memory
----------------
Text output and the final result are also written to memory at $A000,
allowing testing a very minimal emulator that supports little more than
CPU and RAM. To reliably indicate that the data is from a test and not
random data, $A001-$A003 are written with a signature: $DE,$B0,$61. If
this is present, then the text string and final result status are valid.
$A000 holds the overall status. If the test is still running, it holds
$80, otherwise it holds the final result code.
All text output is appended to a zero-terminated string at $A004. An
emulator could regularly check this string for any additional
characters, and output them, allowing real-time text output, rather than
just printing the final output at the end.
GBS versions
------------
Many GBS-based tests require that the GBS player either not interrupt
the init routine with the play routine, or if they do, not interrupt the
play routine again if it hasn't returned yet. This is because many tests
need to run for a while without returning.
In addition to the other text output methods described above, GBS builds
report essential information bytes audibly, including the final result.
A byte is reported as a series of tones. The code is in binary, with a
low tone for 0 and a high tone for 1. The first tone is always a zero. A
final code of 0 means passed, 1 means failure, and 2 or higher indicates
a specific reason as listed in the source code by the corresponding
set_code line. Examples:
Tones Binary Decimal Meaning
- - - - - - - - - - - - - - - - - - - -
low 0 0 passed
low high 01 1 failed
low high low 010 2 error 2
--
Shay Green <gblargg@gmail.com>

View File

@ -0,0 +1,117 @@
; - APU registers always have some bits set when read back.
; - Wave memory can be read back freely.
; - When powered off, registers are cleared, except high bit of NR52.
; - While off, register writes are ignored, but not reads.
; - Wave RAM is always readable and writable, and unaffected by power.
.include "shell.inc"
.include "apu.s"
main:
set_test 2,"NR10-NR51 and wave RAM write/read"
ld d,0
- call test_rw
inc d
jr nz,-
set_test 3,"NR52 write/read"
wreg NR52,$00
lda NR52
cp $70
jp nz,test_failed
wreg NR52,$FF
lda NR52
cp $F0
jp nz,test_failed
set_test 4,"Powering APU shouldn't affect wave"
ld a,$37
call fill_wave
wreg NR52,$00
; Verify that wave RAM is unchanged
ld hl,WAVE
- ld a,(hl+)
cp $37
jp nz,test_failed
ld a,l
cp $40
jr nz,-
wreg NR52,$80 ; on
set_test 5,"Powering APU off should write 0 to all regs"
ld a,$FF
call fill_apu_regs
wreg NR52,$00
wreg NR52,$80
call regs_should_be_clear
set_test 6,"When off, should ignore writes to registers"
wreg NR52,$00
ld a,$FF
call fill_apu_regs
wreg NR52,$80
call regs_should_be_clear
wreg NR52,$80
set_test 7,"When off, should allow normal register reads"
wreg NR52,$00
call regs_should_be_clear
wreg NR52,$80
jp tests_passed
regs_should_be_clear:
ld bc,masks
ld hl,NR10
- ld a,(bc)
cp (hl)
jp nz,test_failed
inc bc
inc l
ld a,l
cp <NR52
jr nz,-
ret
test_rw:
ld bc,masks
ld hl,NR10
- ; Skip NR52
ld a,l
cp <NR52
jr z,+
; A = value that should be read back
ld a,(bc)
or d
; Write then read back and compare
ld (hl),d
cp (hl)
jp nz,test_failed
+ ; Mute channels
wreg NR51,0
; Disable wave, in case it just got enabled
; while testing register
wreg NR30,0
inc bc
inc l
ld a,l
cp <WAVE+$10
jr nz,-
ret
; Registers are ORed with this when reading
masks:
.byte $80,$3F,$00,$FF,$BF ; NR10-NR15
.byte $FF,$3F,$00,$FF,$BF ; NR20-NR25
.byte $7F,$FF,$9F,$FF,$BF ; NR30-NR35
.byte $FF,$FF,$00,$00,$BF ; NR40-NR45
.byte $00,$00,$70 ; NR50-NR52
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.byte $00,$00,$00,$00,$00,$00,$00,$00 ; Wave RAM
.byte $00,$00,$00,$00,$00,$00,$00,$00

View File

@ -0,0 +1,163 @@
; Tests basic length counter operation
.include "shell.inc"
.include "test_chan.s"
main:
test_all_chans
jp tests_passed
begin:
call sync_apu
delay 2048 ; avoid extra clocking due to quirks
wchn 4,$40 ; avoid extra clocking due to quirks
wchn 1,-4 ; length = 4
wchn 4,$C0 ; trigger, enabling channel
ret
should_be_on:
lda chan_mask
ld b,a
lda NR52
and b
jp z,test_failed
ret
should_be_almost_off:
call should_be_on
delay_apu 1
should_be_off:
lda chan_mask
ld b,a
lda NR52
and b
jp nz,test_failed
ret
test_chan:
set_test 2,"Length becoming 0 should clear status"
call begin
delay_apu 3
call should_be_almost_off
set_test 3,"Length can be reloaded at any time"
call begin
wchn 1,-10 ; length = 10
delay_apu 9
call should_be_almost_off
set_test 4,"Attempting to load length with 0 should load with maximum"
call begin
wchn 1,0 ; length = maximum
lda chan_maxlen
dec a
call delay_apu_cycles
call should_be_almost_off
set_test 5,"Trigger shouldn't affect length"
call begin
delay_apu 1
wchn 4,$C0 ; length unaffected
delay_apu 2
call should_be_almost_off
set_test 6,"Trigger should treat 0 length as maximum"
call begin
delay_apu 4 ; clocks length to 0
wchn 4,$C0 ; trigger converts 0 to maximum
lda chan_maxlen
dec a
call delay_apu_cycles
call should_be_almost_off
set_test 7,"Trigger with disabled length should convert ","0 length to maximum"
call begin
delay_apu 4 ; clocks length to 0
wchn 4,$00 ; disable length
wchn 4,$80 ; trigger converts 0 to maximum
wchn 4,$40 ; enable length
lda chan_maxlen
dec a
call delay_apu_cycles
call should_be_almost_off
set_test 8,"Disabling length shouldn't re-enable channel"
call begin
delay_apu 4 ; clocks length to 0
call should_be_off
wchn 4,0 ; disable length
call should_be_off
set_test 9,"Disabling length should stop length clocking"
call begin
wchn 4,0 ; disable length
delay_apu 4 ; length isn't affected
wchn 4,$40 ; enable length
delay_apu 3 ; clocks length to 1
call should_be_almost_off
set_test 10,"Reloading shouldn't re-enable channel"
call begin
delay_apu 4 ; clocks length to 0
call should_be_off
wchn 1,-2 ; length = 2
call should_be_off
set_test 11,"Disabled channel should still clock length"
call begin
delay_apu 4 ; clocks length to 0, disabling channel
wchn 1,-8 ; length = 8
delay_apu 4 ; clocks length to 4
wchn 4,$C0 ; trigger, enabling channel
delay_apu 3 ; clocks length to 1
call should_be_almost_off
set_test 12,"Disabled channel should still convert 0 load to max length"
call begin
delay_apu 4 ; clocks length to 0, disabling channel
wchn 1,0 ; length = maximum
delay_apu 32 ; clock length 32 times
wchn 4,$C0
lda chan_maxlen
sub 33
call delay_apu_cycles
call should_be_almost_off
set_test 13,"Disabling DAC should disable channel immediately"
call begin
delay_apu 2 ; clocks length to 2
call should_be_on
wchn 0,$00 ; if wave channel, this disables DAC
wchn 2,$07 ; if square/noise channel, this disables DAC
call should_be_off
set_test 14,"Disabled DAC should prevent enable at trigger"
call begin
wchn 0,$00 ; if wave channel, this disables DAC
wchn 2,$07 ; if square/noise channel, this disables DAC
wchn 4,$80 ; triggers channel but doesn't enable it
call should_be_off
set_test 15,"Enabling DAC shouldn't re-enable channel"
wchn 0,$80 ; if wave channel, this enables DAC
wchn 2,$10 ; if square/noise channel, this enables DAC
call begin
delay_apu 2
call should_be_on
wchn 0,$00 ; if wave channel, this disables DAC
wchn 2,$00 ; if square/noise channel, this disables DAC
call should_be_off
wchn 0,$80 ; if wave channel, this enables DAC
wchn 2,$10 ; if square/noise channel, this enables DAC
call should_be_off
set_test 16,"Volume reaching 0 shouldn't disable channel"
wchn 2,$11 ; envelope that reaches zero in less than
; 20 length clocks (if wave channel, this just sets
; volume to 0)
call begin
wchn 1,-20
delay_apu 19
call should_be_almost_off
ret

View File

@ -0,0 +1,200 @@
; Verifies length counter clocking during fifth register writes
;.define CGB_02 1
.include "shell.inc"
.include "test_chan.s"
main:
test_all_chans
jp tests_passed
begin:
call sync_apu
wchn 1,-60
wchn 4,$80
ret
end:
delay_clocks 8192+1024 ; so we don't clock length when enabling it below
end_nodelay:
ld b,a
wchn 4,$C0
ld a,b
end_passive:
ld b,a
lda chan_mask
call get_len_a
cp b
jp nz,test_failed
ret
test_chan:
set_test 2,"Enabling in second half of length period ","shouldn't clock length"
call begin
wchn 1,-2 ; length = 2
delay_clocks 8256 ; delay until beginning of second half of length period
wchn 4,$40 ; enable
ld a,2
call end_nodelay
set_test 3,"Enabling in first half of length period should clock length"
call begin
wchn 1,-2 ; length = 2
delay_clocks 7900 ; delay until near-end of first half of length period
wchn 4,$40 ; enable
ld a,1
call end_nodelay
.ifdef CGB_02
set_test 4,"Keeping disabled should clock length; ","disabling or keeping enabled shouldn't"
call begin
wchn 1,-2 ; length = 2
wchn 4,$00 ; disabled -> disabled clocks as well
ld a,1
call end
call begin
wchn 4,$40 ; enable length
wchn 1,-2 ; length = 2
wchn 4,$40 ; enabled -> enabled doesn't clock
wchn 4,$00 ; enabled -> disabled doesn't clock
ld a,2
call end
.else
set_test 4,"Anything besides enabling shouldnt't clock"
call begin
wchn 4,$40 ; enable length
wchn 1,-2 ; length = 2
wchn 4,$40 ; enabled -> enabled doesn't clock
wchn 4,$00 ; enabled -> disabled doesn't clock
wchn 4,$00 ; disabled -> disabled doesn't clock
ld a,2
call end
.endif
set_test 5,"If clock makes length zero, should disable chan"
call begin
wchn 1,-1 ; length = 1
wchn 4,$40 ; enable, causing clock to zero
lda chan_mask
ld b,a
lda NR52 ; channel now disabled
and b
jp nz,test_failed
set_test 6,"If length already reached zero, shouldn't clock"
call begin
wchn 1,-1 ; length = 1
wchn 4,$40 ; enable, causing clock to zero
wchn 4,0
wchn 4,$40 ; no clock; length still 0
wchn 4,0
wchn 4,$40 ; no clock; length still 0
lda chan_maxlen; end triggers channel, which loads it with max length
call end
set_test 7,"Trigger should un-freeze length that reached zero"
call begin
wchn 1,-1 ; length = 1
wchn 4,$40 ; enable, causing clock to zero
wchn 4,$00 ; disable
wchn 4,$80 ; trigger unfreezes length, so it takes on maximum value
delay_clocks 8192
wchn 4,$40 ; enable
delay_apu 2 ; clock length by 2
lda chan_maxlen
sub 2
call end_nodelay
set_test 8,"Trigger that un-freezes enabled length should clock it"
call begin
wchn 1,-1 ; length = 1
wchn 4,$40 ; enable, causing clock to zero
wchn 4,$00 ; disable
wchn 4,$C0 ; trigger unfreezes length, and since enabled, clocks it
lda chan_maxlen
dec a
call end_nodelay
call begin
wchn 1,-1 ; length = 1
wchn 4,$40 ; enable, causing clock to zero
wchn 4,$C0 ; trigger unfreezes length, and since enabled, clocks it
lda chan_maxlen
dec a
call end_nodelay
set_test 9,"Triggering that clocks length of 1 ","should clock twice and shouldn't freeze"
call begin
wchn 1,-1 ; length = 1
wchn 4,$C0 ; trigger and enable
; First length counter is enabled, which clocks it to 0 and freezes it
; Trigger unfreezes length counter, which clocks it AGAIN
; The result is the same as the previous test, which enables separately
lda chan_maxlen
dec a
call end_nodelay
set_test 10,"Trigger shouldn't otherwise affect length"
call begin
wchn 1,0 ; length = max
delay_clocks 8192
wchn 4,$80 ; trigger
lda chan_maxlen
call end_nodelay
.ifndef CGB_02
call begin
wchn 1,0 ; length = max
wchn 4,$80 ; trigger
lda chan_maxlen
call end
call begin
wchn 1,-2 ; length = 2
wchn 4,$80 ; trigger
ld a,2
call end
.endif
set_test 11,"Disabled DAC shouldn't stop other trigger effects"
call begin
wchn 0,$00 ; disable wave DAC
wchn 2,$07 ; disable square/noise DAC
wchn 1,-1
wchn 4,$C0 ; clocks length, which becomes max
wchn 0,$80 ; enable wave DAC
wchn 2,$08 ; enable square/noise DAC
wchn 4,$80 ; trigger
lda chan_maxlen
dec a
call end
set_test 12,"Other trigger effects should still occur when disabled"
call sync_apu
wchn 0,0
wchn 4,0
wchn 1,-1
wchn 4,$40 ; len = 0
wchn 4,0
wchn 4,$40 ; len = 0
wchn 4,$80 ; len = max
wchn 4,$40 ; len = max-1
wchn 4,0
wchn 4,$40 ; len = max-2
wchn 0,$80 ; enable now
wchn 4,$C0
lda chan_maxlen
sub 3
call delay_apu_cycles
lda chan_mask
ld b,a
lda NR52
and b
jp z,test_failed
delay_apu 1
lda NR52
and b
jp nz,test_failed
ret

View File

@ -0,0 +1,120 @@
; Calc = calculation of new frequency and check for > $7FF
; Update = modification of frequency with new calculated value
.include "shell.inc"
.include "apu.s"
begin:
call sync_sweep
wreg NR14,$40
wreg NR11,-$21
wreg NR12,$08
ret
should_be_almost_off:
lda NR52
and $01
jp z,test_failed
delay_apu 1
should_be_off:
lda NR52
and $01
jp nz,test_failed
ret
main:
set_test 2,"If shift>0, calculates on trigger"
call begin
wreg NR10,$01
wreg NR13,$FF
wreg NR14,$C7
call should_be_off
call begin
wreg NR10,$11
wreg NR13,$FF
wreg NR14,$C7
call should_be_off
set_test 3,"If shift=0, doesn't calculate on trigger"
call begin
wreg NR10,$10
wreg NR13,$FF
wreg NR14,$C7
delay_apu 1
call should_be_almost_off
set_test 4,"If period=0, doesn't calculate"
call begin
wreg NR10,$00
wreg NR13,$FF
wreg NR14,$C7
delay_apu $20
call should_be_almost_off
set_test 5,"After updating frequency, calculates a second time"
call begin
wreg NR10,$11
wreg NR13,$00
wreg NR14,$C5
delay_apu 1
call should_be_almost_off
set_test 6,"If calculation>$7FF, disables channel"
call begin
wreg NR10,$02
wreg NR13,$67
wreg NR14,$C6
call should_be_off
set_test 7,"If calculation<=$7FF, doesn't disable channel"
call begin
wreg NR10,$01
wreg NR13,$55
wreg NR14,$C5
delay_apu $20
call should_be_almost_off
set_test 8,"If shift=0 and period>0, trigger enables"
call begin
wreg NR10,$10
wreg NR13,$FF
wreg NR14,$C3
delay_apu 2
wreg NR10,$11
delay_apu 1
call should_be_almost_off
set_test 9,"If shift>0 and period=0, trigger enables"
call begin
wreg NR10,$01
wreg NR13,$FF
wreg NR14,$C3
delay_apu 15
wreg NR10,$11
call should_be_almost_off
set_test 10,"If shift=0 and period=0, trigger disables"
call begin
wreg NR10,$08
wreg NR13,$FF
wreg NR14,$C3
wreg NR10,$11
delay_apu $20
call should_be_almost_off
set_test 11,"If shift=0, doesn't update"
call begin
wreg NR10,$10
wreg NR13,$FF
wreg NR14,$C3
delay_apu $20
call should_be_almost_off
set_test 12,"If period=0, doesn't update"
call begin
wreg NR10,$01
wreg NR13,$00
wreg NR14,$C5
delay_apu $20
call should_be_almost_off
jp tests_passed

View File

@ -0,0 +1,121 @@
; Calc = calculation of new frequency and check for > $7FF
; Update = modification of frequency with new calculated value
.include "shell.inc"
.include "apu.s"
begin:
call sync_sweep
wreg NR14,$40
wreg NR11,-$20
wreg NR12,$08
ret
should_be_almost_off:
lda NR52
and $01
jp z,test_failed
delay_apu 1
should_be_off:
lda NR52
and $01
jp nz,test_failed
ret
main:
set_test 2,"Timer treats period 0 as 8"
call begin
wreg NR10,$11
wreg NR13,$00
wreg NR14,$C2
delay_apu 1
wreg NR10,$01 ; sweep enabled
delay_apu 3
wreg NR10,$11 ; non-zero period so calc will occur when timer reloads
delay_apu $11
call should_be_almost_off
set_test 3,"Makes private copy of frequency on trigger"
call begin
wreg NR10,$12
wreg NR13,$04
wreg NR14,$80
wreg NR13,$00
delay_apu $39
call should_be_almost_off
set_test 4,"Exiting negate mode after calculation disables channel"
call begin
wreg NR10,$09 ; since shift > 0, calculates sweep value at init
wreg NR13,$00
wreg NR14,$C0
delay_apu 2
wreg NR10,$10 ; neg->pos, so disables channel
call should_be_off
set_test 5,"Ending negate after it maybe changed freq disables chan"
call begin
wreg NR10,$10 ; enable sweep
wreg NR13,$00
wreg NR14,$C0
delay_apu 2
wreg NR10,$18 ; negate mode
delay_apu 2
wreg NR10,$10 ; neg->pos, so disables channel
call should_be_off
set_test 6,"Ending negate mode any other way doesn't disable channel"
call begin
wreg NR10,$1F ; use negate mode once
wreg NR14,$C0
delay_apu 2
wreg NR10,$18 ; since period > 0, doesn't calculate at init
wreg NR13,$00
wreg NR14,$C0
delay_apu 1 ; no sweep clock here
wreg NR10,$10 ; pos mode before neg mode ever used
delay_apu 1 ; sweep clock occurs here
wreg NR10,$0F ; now let neg mode be seen once, but period = 0 so no calculation is made
delay_apu 2 ; sweep clock occurs here
wreg NR10,$10 ; doesn't affect channel
delay_apu 2 ; sweep clock occurs here
wreg NR10,$1F ; let neg mode get used
delay_apu 18
wreg NR10,$79 ; period and shift can be changed without channel disabling
delay_apu 5
call should_be_almost_off
set_test 7,"Subtract mode uses two's complement"
call begin
delay 2048 ; avoids extra length clocking on CGB-02
wreg NR10,$1C
wreg NR13,$B0
wreg NR14,$85
delay_apu 2
wreg NR10,$01
wreg NR14,$C5
delay_apu $1F
call should_be_almost_off
set_test 8,"Subtract mode uses two's complement (upper bound)"
call begin
wreg NR10,$1C
wreg NR13,$B1
wreg NR14,$85
delay_apu 2
wreg NR10,$01
wreg NR14,$C5
call should_be_off
set_test 9,"Update channel frequency only when period is reloaded"
call begin
wreg NR10,$74
wreg NR13,$06
wreg NR14,$85
delay_apu 14 ; just reloaded
wreg NR13,$06
delay_apu 13 ; if 14, fails
wreg NR10,$11
wreg NR14,$85 ; just before next reload, so freq is still $506
call should_be_almost_off
jp tests_passed

View File

@ -0,0 +1,64 @@
; Finds highest and lowest frequencies that don't overflow
; immediately on trigger, for NR10 values of $00-$07
.include "shell.inc"
.include "apu.s"
main:
; DMG-06:
; 0555 0666 071C 0787 07C1 07E0 07F0
wreg NR12,8
ld d,$01
shift_loop:
ld a,d
sta NR10
ld bc,$87FF
- ld a,c
sta NR13
ld a,b
sta NR14
delay_clocks 40
lda NR52
and 1
jr nz,+
dec bc
bit 6,b
jr z,-
+ res 7,b
call print_bc
inc d
bit 3,d
jr z,shift_loop
call print_newline
check_crc $F604603B
; DMG-05, DMG-06, DMG-09, CGB-04, CGB-05:
; 0556 0667 071D 0788 07C2 07E1 07F1
wreg NR12,8
ld d,$01
shift_loop2:
ld a,d
sta NR10
ld bc,$8000
- ld a,c
sta NR13
ld a,b
sta NR14
delay_clocks 40
lda NR52
and 1
jr z,+
inc bc
bit 6,b
jr z,-
+ res 7,b
call print_bc
inc d
bit 3,d
jr z,shift_loop2
check_crc $5A1697EE
jp tests_passed

View File

@ -0,0 +1,106 @@
; Tests length and sweep periods, and synchronization between the two
.include "shell.inc"
.include "apu.s"
test_timing:
; Time how long until next length clock
- inc de
ld a,(NR52)
and $01
jr nz,-
;call print_de
; Error if not in 0...4 range
ld a,d
cp 0
jp nz,test_failed
ld a,e
cp 5
jp nc,test_failed
ret
main:
set_test 2,"Length period is wrong"
call sync_apu
wreg NR14,$40 ; avoids extra length clock
wreg NR11,$3F ; length = $01
wreg NR12,$08 ; silent without disabling channel
wreg NR14,$C0 ; start length
ld de,-$170
call test_timing
set_test 3,"Sweep period is wrong"
call sync_sweep
wreg NR10,$10 ; sweep period = 1
wreg NR12,$08 ; silent without disabling channel
wreg NR13,$FF ; max freq
wreg NR14,$87 ; start
ld de,-$2E4
call test_timing
set_test 4,"Sweep clock is synchronized with length"
call sync_sweep
wreg NR14,$40 ; avoids extra length clock
wreg NR11,$3F ; length = $01
wreg NR12,$08 ; silent without disabling channel
wreg NR14,$C0 ; start length
ld de,-$170
call test_timing
set_test 5,"Powering up APU MODs next frame time with 8192"
call sync_apu
ld de,-$16F
call test_power
call sync_apu
ld de,-$B5
call test_power_off
call sync_apu
delay_clocks 8192
ld de,-$B5
call test_power
call sync_apu
delay_clocks 8192
ld de,-$B5
call test_power_off
call sync_apu
ld de,-$B5
wreg NR52,$00 ; power off
delay_clocks 8192
call test_power
set_test 6,"Powering up APU resets 128 Hz sweep divider"
call sync_sweep
ld de,-$229
call test_power2
call sync_sweep
delay_apu 1
ld de,-$229
call test_power2
jp tests_passed
test_power_off:
wreg NR52,$00 ; power off
test_power:
wreg NR52,$80 ; power on
wreg NR14,$40
wreg NR11,-1 ; length = 1
wreg NR12,8
wreg NR14,$C0
jp test_timing
test_power2:
wreg NR52,$00 ; power off
wreg NR52,$80 ; power on
wreg NR10,$11
wreg NR12,8
wreg NR13,$00
wreg NR14,$84
jp test_timing

View File

@ -0,0 +1,84 @@
; On CGB, length counters are reset when powered up.
; On DMG, they are unaffected, and not clocked.
;.define REQUIRE_DMG 1
;.define REQUIRE_CGB 1
.include "shell.inc"
.include "apu.s"
enable_len_ctrs:
wreg NR22,8
wreg NR24,$C0
wreg NR12,8
wreg NR14,$C0
wreg NR30,$80
wreg NR34,$C0
wreg NR42,8
wreg NR44,$C0
ret
main:
call sync_apu
ld a,0
call fill_apu_regs
; Load length counters
wreg NR41,-$33
wreg NR31,-$44
wreg NR11,-$11
wreg NR21,-$22
delay_clocks 8192
call enable_len_ctrs
; Power down. Comment out to see what would
; happen if length counters did run.
wreg NR52,$00
; Try to enable length counters
call enable_len_ctrs
; Give plenty of time for them to be clocked
delay_msec 250
; Power back on and wait a bit longer
wreg NR52,$80
;call enable_len_ctrs ; can't do this here
delay_clocks 2048
; Get values from length counters
wreg NR22,8
wreg NR24,$C0
ld a,$02
call get_len_a
push af
wreg NR12,8
wreg NR14,$C0
ld a,$01
call get_len_a
push af
wreg NR30,$80
wreg NR34,$C0
ld a,$04
call get_len_a
push af
wreg NR42,8
wreg NR44,$C0
ld a,$08
call get_len_a
; Print them
call print_a
pop af
call print_a
pop af
call print_a
pop af
call print_a
check_crc_dmg_cgb $32F0CFBB,$3CF589B4
jp tests_passed

View File

@ -0,0 +1,41 @@
; Reads from wave RAM while playing, each time 2
; clocks later.
;.define REQUIRE_DMG 1
;.define REQUIRE_CGB 1
.include "shell.inc"
.include "apu.s"
main:
wreg NR51,0 ; mute sound
loop_n_times test,69
check_crc_dmg_cgb $118A3620,$270DA9A3
jp tests_passed
test:
add $99
ld b,a
; Reload wave and have its first
; sample read occur 2 clocks earlier
; each loop iteration
ld hl,wave
call load_wave
wreg NR30,$80 ; enable
wreg NR32,$00 ; silent
ld a,b
sta NR33 ; period
wreg NR34,$87 ; start
; Read from wave
wreg NR33,-2 ; period = 4
delay_clocks 176
lda WAVE
call print_a
ret
wave:
.byte $00,$11,$22,$33,$44,$55,$66,$77
.byte $88,$99,$AA,$BB,$CC,$DD,$EE,$FF

View File

@ -0,0 +1,49 @@
; Retriggers wave without stopping first
;.define REQUIRE_DMG 1
;.define REQUIRE_CGB 1
.include "shell.inc"
.include "apu.s"
main:
wreg NR51,0 ; mute sound
loop_n_times test,69
check_crc_dmg_cgb $533D6D4D,$8130733A
jp tests_passed
test:
add $99
ld b,a
; Reload wave and have its first
; sample read occur 2 clocks earlier
; each loop iteration
ld hl,wave
call load_wave
wreg NR30,$80 ; enable
wreg NR32,$00 ; silent
ld a,b
sta NR33 ; period
wreg NR34,$87 ; start
; Retrigger wave
wreg NR33,-2 ; period = 4
delay_clocks 168
wreg NR34,$87 ; restart
delay_clocks 40
; Print wave RAM
wreg NR30,0
ld c,$30
- ld a,($FF00+c)
call print_a
inc c
bit 6,c
jr z,-
call print_newline
ret
wave:
.byte $00,$11,$22,$33,$44,$55,$66,$77
.byte $88,$99,$AA,$BB,$CC,$DD,$EE,$FF

View File

@ -0,0 +1,51 @@
; After powering sound off then on, NR12, NR14, and NR44
; are clear.
.define REQUIRE_CGB 1
.include "shell.inc"
.include "apu.s"
main:
call sync_apu
ld a,$FF
call fill_apu_regs
; Power down for a moment
wreg NR52,$00
wreg NR41,-$12
wreg NR12,$F0
delay_msec 100
wreg NR52,$80
set_test 2,"Powering off should clear NR12"
call sync_apu
wreg NR14,$80
lda NR52
and $01
jp nz,test_failed
set_test 3,"Powering off should clear NR13"
call sync_apu
wreg NR10,$11
wreg NR12,$08
wreg NR14,$80
delay_apu 20
lda NR52
and $01
jp z,test_failed
set_test 4,"Powering off should clear NR41"
call sync_apu
delay_clocks 8192 ; avoids extra length clocking
wreg NR42,$08
wreg NR44,$C0
delay_apu 63
lda NR52
and $08
jp z,test_failed
delay_apu 1
lda NR52
and $08
jp nz,test_failed
jp tests_passed

View File

@ -0,0 +1,112 @@
; Tests wave channel timer reload and phase rest on trigger,
; and access to wave RAM while playing.
.define REQUIRE_CGB 1
.include "shell.inc"
.include "apu.s"
main:
ld hl,wave
call load_wave
wreg NR32,0
set_test 2,"Timer period or phase resetting is wrong"
wreg NR30,$80
wreg NR33,$00
wreg NR34,$80
delay_clocks 1024
wreg NR34,$80
ld c,$31
ld de,-$FE
call test_wave
set_test 3,"Current byte readable at any wave addr"
wreg NR30,$80
wreg NR33,$00
wreg NR34,$80
ld c,$3C
ld de,-$FE
call test_wave
set_test 5,"Normal access when chan disabled"
wreg NR30,$80
wreg NR33,$00
wreg NR34,$80
wreg NR30,$00 ; disable chan
wreg NR30,$80 ; DAC on
ld c,$31
ld de,0
call test_wave
set_test 6,"Write test"
wreg NR30,$80
wreg NR33,$F0
wreg NR34,$87
delay_clocks 256
wreg $FF30,$BC
wreg NR30,0
ld a,($FF34)
cp $BC
jp nz,test_failed
set_test 7,"Timer period change"
wreg NR30,$80
wreg NR33,$00
wreg NR34,$87
wreg NR33,$F0
ld c,$30
ld de,-$E
call test_wave
set_test 8,"Frequency 0 is valid"
wreg NR30,$80
wreg NR33,$00
wreg NR34,$80
ld c,$30
ld de,-$FE
call test_wave
set_test 9,"Maintains phase properly when vol = 0"
wreg NR30,$80
wreg NR32,0
wreg NR33,$00
wreg NR34,$87
ld c,$30
ld de,-$1E
call test_wave
set_test 10,"Maintains phase properly when stereo = 0"
wreg NR51,$00
wreg NR30,$80
wreg NR33,$00
wreg NR34,$87
ld c,$30
ld de,-$1E
call test_wave
jp tests_passed
test_wave:
- inc de ; 8
ld a,($FF00+c) ; 8
or a ; 4
jr z,- ; 12
;call print_a
;call print_de
cp $11
jp nz,test_failed
; Error if not in 0...4 range
ld a,d
cp 0
jp nz,test_failed
ld a,e
cp 5
jp nc,test_failed
ret
wave:
.byte $00,$11,$22,$33,$44,$55,$66,$77
.byte $88,$99,$AA,$BB,$CC,$DD,$EE,$FF

View File

@ -0,0 +1,139 @@
; Build as GBS music file
.memoryMap
defaultSlot 0
slot 0 $2000 size $2000
slot 1 $C000 size $2000
.endMe
.romBankSize $2000
.romBanks 2
.define RST_OFFSET $70
.ifndef GBS_TMA
.define GBS_TMA 0
.endif
.ifndef GBS_TAC
.define GBS_TAC 0
.endif
;;;; GBS music file header
.ifndef CUSTOM_HEADER
.byte "GBS"
.byte 1,1,1 ; vers, song count, first song
.word load_addr, reset, gbs_play_, std_stack
.byte GBS_TMA,GBS_TAC ; timer
.endif
.org $10
.ds $60,0
load_addr:
.org RST_OFFSET+$70 ; space for RST vectors
.ds $148-RST_OFFSET-$70,0
.org $150 ; wla insists on generating GB header
gbs_play_:
jp gbs_play ; GBS spec disallows having gbs_play in RAM
;;;; Shell
.include "shell.s"
.define gbs_idle nv_ram
.redefine nv_ram nv_ram+2
init_runtime:
; Identify as DMG hardware
ld a,$01
ld (gb_id),a
; Save return address
pop hl
ld a,l
ld (gbs_idle),a
ld a,h
ld (gbs_idle+1),a
; Delay 1/4 second to give time
; for GBS player to interrupt with
; play, if it's going to do so
delay_msec 250
.ifndef CUSTOM_PLAY
gbs_play:
.endif
; Get return address
ld a,(gbs_idle)
ld l,a
ld a,(gbs_idle+1)
ld h,a
; If zero, then play interrupted init
; call, or another play call, and we
; can't run the program properly.
or l
jp z,internal_error
setw gbs_idle,0
jp hl
; Reports A in binary as high and low tones, with
; leading low tone for reference. Omits leading
; zeroes.
; Preserved: AF, BC, DE, HL
play_byte:
push af
push hl
; HL = (A << 1) | 1
scf
rla
ld l,a
ld h,0
rl h
; Shift left until next-to-top bit is 1
- add hl,hl
bit 6,h
jr z,-
; Reset sound
delay_msec 400
wreg NR52,0 ; sound off
wreg NR52,$80 ; sound on
wreg NR51,$FF ; mono
wreg NR50,$77 ; volume
- add hl,hl
; Low or high pitch based on bit shifted out
; of HL
ld a,0
jr nc,+
ld a,$FF
+ sta NR23
; Play short tone
wreg NR21,$A0
wreg NR22,$F0
wreg NR24,$86
delay_msec 75
wreg NR22,0
wreg NR23,$F8
wreg NR24,$87
delay_msec 200
; Loop until HL = $8000
ld a,h
xor $80
or l
jr nz,-
pop hl
pop af
ret
.ends

View File

@ -0,0 +1,70 @@
; Build as GB ROM
.memoryMap
defaultSlot 0
slot 0 $0000 size $4000
slot 1 $C000 size $4000
.endMe
.romBankSize $4000
.romBanks 2
.cartridgeType 2 ; MBC1+RAM
.ramsize 02 ; 8K
.computeChecksum
.computeComplementCheck
;;;; GB ROM header
; Reserve space for RST handlers
.org $70
; Keep unused space filled, otherwise
; wla moves code here
.ds $90,0
; GB header read by bootrom
.org $100
nop
jp reset
; Nintendo logo required for proper boot
.byte $CE,$ED,$66,$66,$CC,$0D,$00,$0B
.byte $03,$73,$00,$83,$00,$0C,$00,$0D
.byte $00,$08,$11,$1F,$88,$89,$00,$0E
.byte $DC,$CC,$6E,$E6,$DD,$DD,$D9,$99
.byte $BB,$BB,$67,$63,$6E,$0E,$EC,$CC
.byte $DD,$DC,$99,$9F,$BB,$B9,$33,$3E
; Internal name
.ifdef ROM_NAME
.byte ROM_NAME
.endif
; CGB/DMG requirements
.org $143
.ifdef REQUIRE_CGB
.byte $C0
.else
.ifndef REQUIRE_DMG
.byte $80
.endif
.endif
; Keep unused space filled, otherwise
; wla moves code here
.org $150
.ds $2150-$150,0
;;;; Shell
.define NEED_CONSOLE 1
.include "shell.s"
init_runtime:
ret
play_byte:
ret
.ends

View File

@ -0,0 +1,285 @@
; Scrolling text console
; Console is 20x18 characters. Buffers lines, so
; output doesn't appear until a newline or flush.
; If scrolling isn't supported (i.e. SCY is treated
; as if always zero), the first 18 lines will
; still print properly). Also works properly if
; LY isn't supported (always reads back as the same
; value).
.define console_width 20
.define console_buf bss+0
.define console_pos bss+console_width
.define console_mode bss+console_width+1
.define console_scroll bss+console_width+2
.redefine bss bss+console_width+3
; Waits for start of LCD blanking period
; Preserved: BC, DE, HL
console_wait_vbl:
push bc
; Wait for start of vblank, with
; timeout in case LY doesn't work
; or LCD is disabled.
ld bc,-1250
- inc bc
ld a,b
or c
jr z,@timeout
lda LY
cp 144
jr nz,-
@timeout:
pop bc
ret
; Initializes text console
console_init:
call console_hide
; CGB-specific inits
ld a,(gb_id)
and gb_id_cgb
call nz,@init_cgb
; Clear nametable
ld a,' '
call @fill_nametable
; Load tiles
ld hl,TILES+$200
ld c,0
call @load_tiles
ld hl,TILES+$A00
ld c,$FF
call @load_tiles
; Init state
setb console_pos,console_width
setb console_mode,0
setb console_scroll,-8
call console_scroll_up_
jr console_show
@fill_nametable:
ld hl,BGMAP0
ld b,4
- ld (hl),a
inc l
jr nz,-
inc h
dec b
jr nz,-
ret
@init_cgb:
; Clear palette
wreg $FF68,$80
ld b,16
- wreg $FF69,$FF
wreg $FF69,$7F
wreg $FF69,$00
wreg $FF69,$00
wreg $FF69,$00
wreg $FF69,$00
wreg $FF69,$00
wreg $FF69,$00
dec b
jr nz,-
; Clear attributes
wreg VBK,1
ld a,0
call @fill_nametable
wreg VBK,0
ret
@load_tiles:
ld de,ASCII
ld b,96
-- push bc
ld b,8
- ld a,(de)
inc de
xor c
ldi (hl),a
ldi (hl),a
dec b
jr nz,-
pop bc
dec b
jr nz,--
ret
; Shows console display
; Preserved: AF, BC, DE, HL
console_show:
push af
; Enable LCD
call console_wait_vbl
wreg LCDC,$91
wreg SCX,0
wreg BGP,$E4
jp console_apply_scroll_
; Hides console display by turning LCD off
; Preserved: AF, BC, DE, HL
console_hide:
push af
; LCD off
call console_wait_vbl
wreg LCDC,$11
pop af
ret
; Changes to normal text mode
; Preserved: BC, DE, HL
console_normal:
xor a
jr console_set_mode
; Changes to inverse text mode
; Preserved: BC, DE, HL
console_inverse:
ld a,$80
; Changes console mode to A.
; 0: Normal, $80: Inverse
; Preserved: BC, DE, HL
console_set_mode:
and $80
ld (console_mode),a
ret
; Prints char A to console. Will not appear until
; a newline or flush occurs.
; Preserved: AF, BC, DE, HL
console_print:
push af
cp 10
jr z,console_newline_
push hl
push af
ld hl,console_pos
ldi a,(hl)
cp <console_buf
jr nz,@not_at_end
; Newline if at end of current line. If this
; were done after writing to buffer, calling
; console_newline would print extra newline.
; Doing it before eliminates this.
; Ignore any spaces at end of line
pop af
cp ' '
jr z,@ignore_space
call console_newline
push af
@not_at_end:
pop af
or (hl) ; apply current attributes
dec l ; hl = console_pos
dec (hl) ; console_pos = console_pos - 1
ld l,(hl) ; hl = position in buffer
ld (hl),a
@ignore_space
pop hl
pop af
ret
; Displays current line and starts new one
; Preserved: AF, BC, DE, HL
console_newline:
push af
console_newline_:
call console_wait_vbl
call console_flush_
call console_scroll_up_
call console_flush_
jp console_apply_scroll_
console_scroll_up_:
push bc
push hl
; Scroll up 8 pixels
ld a,(console_scroll)
add 8
ld (console_scroll),a
; Start new clear line
ld a,' '
ld hl,console_buf + console_width - 1
ld b,console_width
- ldd (hl),a
dec b
jr nz,-
setb console_pos,<(console_buf + console_width)
pop hl
pop bc
ret
; Displays current line's contents without scrolling.
; Preserved: A, BC, DE, HL
console_flush:
push af
call console_wait_vbl
call console_flush_
console_apply_scroll_:
ld a,(console_scroll)
sub 136
sta SCY
pop af
ret
console_flush_:
push de
push hl
; Address of row in nametable
ld a,(console_scroll)
ld l,a
ld h,(>BGMAP0) >> 2
add hl,hl
add hl,hl
; Copy line
ld de,console_buf + console_width
- dec e
ld a,(de)
ldi (hl),a
ld a,e
cp <console_buf
jr nz,-
pop hl
pop de
ret
ASCII:
.incbin "console.bin"

View File

@ -0,0 +1,78 @@
; CRC-32 checksum calculation
.define checksum dp+0 ; little-endian, complemented
.redefine dp dp+4
; Initializes checksum module. Might initialize tables
; in the future.
init_crc:
jr reset_crc
; Clears CRC
; Preserved: BC, DE, HL
reset_crc:
ld a,$FF
sta checksum+0
sta checksum+1
sta checksum+2
sta checksum+3
ret
; Updates current checksum with byte A
; Preserved: AF, BC, DE, HL
; Time: 237 cycles average
update_crc:
; 65 cycles + 8*cycles per bit
; min cycles per bit: 14
; max cycles per bit: 29
push af
push bc
push de
push hl
ld hl,checksum+3
ld b,(hl)
dec l
ld c,(hl)
dec l
ld d,(hl)
dec l
xor (hl)
ld h,8
- srl b
rr c
rr d
rra
jr nc,+
ld e,a
ld a,b
xor $ED
ld b,a
ld a,c
xor $B8
ld c,a
ld a,d
xor $83
ld d,a
ld a,e
xor $20
+ dec h
jr nz,-
ld h,>checksum
ldi (hl),a
ld (hl),d
inc l
ld (hl),c
inc l
ld (hl),b
pop hl
pop de
pop bc
pop af
ret

View File

@ -0,0 +1,220 @@
; Delays in cycles, milliseconds, etc.
; All routines are re-entrant (no global data). Routines never
; touch BC, DE, or HL registers. These ASSUME CPU is at normal
; speed. If running at double speed, msec/usec delays are half advertised.
; Delays n cycles, from 0 to 16777215
; Preserved: AF, BC, DE, HL
.macro delay ARGS n
.if n < 0
.printt "Delay must be >= 0"
.fail
.endif
.if n > 16777215
.printt "Delay must be < 16777216"
.fail
.endif
delay_ n&$FFFF, n>>16
.endm
; Delays n clocks, from 0 to 16777216*4. Must be multiple of 4.
; Preserved: AF, BC, DE, HL
.macro delay_clocks ARGS n
.if n # 4 != 0
.printt "Delay must be a multiple of 4"
.fail
.endif
delay_ (n/4)&$FFFF,(n/4)>>16
.endm
; Delays n microseconds (1/1000000 second)
; n can range from 0 to 4000 usec.
; Preserved: AF, BC, DE, HL
.macro delay_usec ARGS n
.if n < 0
.printt "Delay must be >= 0"
.fail
.endif
.if n > 4000
.printt "Delay must be <= 4000 usec"
.fail
.endif
delay_ ((n * 1048576 + 500000) / 1000000)&$FFFF,((n * 1048576 + 500000) / 1000000)>>16
.endm
; Delays n milliseconds (1/1000 second)
; n can range from 0 to 10000 msec.
; Preserved: AF, BC, DE, HL
.macro delay_msec ARGS n
.if n < 0
.printt "Delay must be >= 0"
.fail
.endif
.if n > 10000
.printt "Delay must be <= 10000 msec"
.fail
.endif
delay_ ((n * 1048576 + 500) / 1000)&$FFFF, ((n * 1048576 + 500) / 1000)>>16
.endm
; All the low/high quantities are to deal wla-dx's asinine
; restriction full expressions must evaluate to a 16-bit
; value. If the author ever rectifies this, all "high"
; arguments can be treated as zero and removed. Better yet,
; I'll just find an assembler that didn't crawl out of
; the sewer (this is one of too many bugs I've wasted
; hours working around).
.define max_short_delay 28
.macro delay_long_ ARGS n, high
; 0+ to avoid assembler treating as memory read
ld a,0+(((high<<16)+n) - 11) >> 16
call delay_65536a_9_cycles_
delay_nosave_ (((high<<16)+n) - 11)&$FFFF, 0
.endm
; Doesn't save AF, allowing minimization of AF save/restore
.macro delay_nosave_ ARGS n, high
; 65536+11 = maximum delay using delay_256a_9_cycles_
; 255+22 = maximum delay using delay_a_20_cycles
; 22 = minimum delay using delay_a_20_cycles
.if high > 1
delay_long_ n, high
.else
.if high*n > 11
delay_long_ n, high
.else
.if (high*(255+22+1))|n > 255+22
ld a,>(((high<<16)+n) - 11)
call delay_256a_9_cycles_
delay_nosave_ <(((high<<16)+n) - 11), 0
.else
.if n >= 22
ld a,n - 22
call delay_a_20_cycles
.else
delay_short_ n
.endif
.endif
.endif
.endif
.endm
.macro delay_ ARGS low, high
.if (high*(max_short_delay+1))|low > max_short_delay
push af
delay_nosave_ ((high<<16)+low - 7)&$FFFF, ((high<<16)+low - 7)>>16
pop af
.else
delay_short_ low
.endif
.endm
; Delays A cycles + overhead
; Preserved: BC, DE, HL
; Time: A+20 cycles (including CALL)
delay_a_20_cycles:
- sub 5 ; 2
jr nc,- ;3/2 do multiples of 5
rra ; 1
jr nc,+ ;3/2 bit 0
+ adc 1 ; 2
ret nc ;5/2 -1: 0 cycles
ret z ;5/2 0: 2 cycles
nop ; 1 1: 4 cycles
ret ; 4 (thanks to dclxvi for original algorithm)
; Delays A*256 cycles + overhead
; Preserved: BC, DE, HL
; Time: A*256+12 cycles (including CALL)
delay_256a_12_cycles:
or a ; 1
ret z ; 5/2
delay_256a_9_cycles_:
- delay 256-4
dec a ; 1
jr nz,- ;3/2
ret ; 4
; Delays A*65536 cycles + overhead
; Preserved: BC, DE, HL
; Time: A*65536+12 cycles (including CALL)
delay_65536a_12_cycles:
or a ; 1
ret z ;5/2
delay_65536a_9_cycles_:
- delay 65536-4
dec a ; 1
jr nz,- ;3/2
ret ; 4
; Delays H*256+L cycles + overhead
; Preserved: AF, BC, DE, HL
; Time: H*256+L+51 cycles
delay_hl_51_cycles:
push af
ld a,h
call delay_256a_12_cycles
ld a,l
call delay_a_20_cycles
pop af
ret
; delay_short_ macro calls into these
.ds max_short_delay-10,$00 ; NOP repeated several times
delay_unrolled_:
ret
.macro delay_short_ ARGS n
.if n < 0
.fail
.endif
.if n > max_short_delay
.fail
.endif
.if n == 1
nop
.endif
.if n == 2
nop
nop
.endif
.if n == 3
.byte $18,$00 ; JR +0
.endif
.if n == 4
.byte $18,$00 ; JR +0
nop
.endif
.if n == 5
.byte $18,$00 ; JR +0
nop
nop
.endif
.if n == 6
.byte $18,$00 ; JR +0
.byte $18,$00 ; JR +0
.endif
.if n == 7
push af
pop af
.endif
.if n == 8
push af
pop af
nop
.endif
.if n == 9
push af
pop af
nop
nop
.endif
.if n >= 10
call delay_unrolled_ + 10 - n
.endif
.endm

View File

@ -0,0 +1,81 @@
; Game Boy hardware addresses
; $0000-$3FFF Fixed ROM bank
; $4000-$7FFF Switchable bank
; $8000-$9FFF VRAM
; $A000-$BFFF optional cartridge RAM
; $C000-$DFFF RAM
; $E000-$FDFF RAM mirror
; $FE00-$FE9F OAM
; $FEA0-$FEFF unused
; $FF00-$FF7F registers
; $FF80-$FFFE RAM
; $FFFF register
; Memory
.define VRAM $8000 ; video memory
.define TILES $8000 ; tile images
.define BGMAP0 $9800 ; first 32x32 tilemap
.define BGMAP1 $9C00 ; second 32x32 tilemap
.define BRAM $A000 ; cart memory
.define WRAM $C000 ; internal memory
.define OAM $FE00 ; sprite memory
.define HRAM $FF80 ; fast memory for LDH
; Registers
.define RAMEN $0000 ; cartridge WRAM control
.define BANK $2000 ; bank select
.define P1 $FF00 ; controller
; Game link I/O
.define SB $FF01 ; serial buffer
.define SC $FF02 ; serial control
; Interrupts
.define DIV $FF04
.define TIMA $FF05
.define TMA $FF06
.define TAC $FF07
.define IF $FF0F
.define IE $FFFF
; LCD registers
.define LCDC $FF40 ; control
.define STAT $FF41 ; status
.define SCY $FF42 ; scroll Y
.define SCX $FF43 ; scroll X
.define LY $FF44 ; current Y being rendered
.define BGP $FF47
.define KEY1 $FF4D ; for changing CPU speed
.define VBK $FF4F
; Sound registers
.define NR10 $FF10
.define NR11 $FF11
.define NR12 $FF12
.define NR13 $FF13
.define NR14 $FF14
.define NR21 $FF16
.define NR22 $FF17
.define NR23 $FF18
.define NR24 $FF19
.define NR30 $FF1A
.define NR31 $FF1B
.define NR32 $FF1C
.define NR33 $FF1D
.define NR34 $FF1E
.define NR41 $FF20
.define NR42 $FF21
.define NR43 $FF22
.define NR44 $FF23
.define NR50 $FF24
.define NR51 $FF25
.define NR52 $FF26
.define WAVE $FF30

View File

@ -0,0 +1,91 @@
; General macros
; Reads A from addr, from $FF00 to $FFFF
; Preserved: F, BC, DE, HL
; Time: 3 cycles
.macro lda ; addr
ldh a,(\1 - $FF00)
.endm
; Writes A to addr, from $FF00 to $FFFF
; Preserved: AF, BC, DE, HL
; Time: 3 cycles
.macro sta ; addr
ldh (\1 - $FF00),a
.endm
; Writes immediate data to addr, from $FF00 to $FFFF
; Preserved: F, BC, DE, HL
; Time: 5 cycles
.macro wreg ARGS addr, data
ld a,data
sta addr
.endm
; Writes byte to addr
; Preserved: F, BC, DE, HL
; Time: 6 cycles
.macro setb ; addr, data
ld a,\2
ld (\1),a
.endm
; Writes word to addr
; Preserved: F, BC, DE, HL
; Time: 12 cycles
.macro setw ; addr, data
ld a,<\2
ld (\1),a
ld a,>\2
ld (\1+1),a
.endm
; Calls routine multiple times, with A having the
; value 'start' the first time, 'start+step' the
; second time, up to 'end' for the last time.
; Preserved: BC, DE, HL
.macro for_loop ; routine,start,end,step
ld a,\2
for_loop\@:
push af
call \1
pop af
add \4
cp <(\3 + \4)
jr nz,for_loop\@
.endm
; Calls routine n times. The value of A in the routine
; counts from 0 to n-1.
; Preserved: BC, DE, HL
.macro loop_n_times ; routine,n
for_loop \1,0,\2 - 1,+1
.endm
; Same as for_loop, but counts with 16-bit value in BC.
; Preserved: DE, HL
.macro for_loop16 ; routine,start,end,step
ld bc,\2
for_loop16\@:
push bc
call \1
pop bc
ld a,c
add <\4
ld c,a
ld a,b
adc >\4
ld b,a
cp >(\3+\4)
jr nz,for_loop16\@
ld a,c
cp <(\3+\4)
jr nz,for_loop16\@
.endm

View File

@ -0,0 +1,177 @@
; Printing of numeric values
; Prints value of indicated register/pair
; as 2/4 hex digits, followed by a space.
; Updates checksum with printed values.
; Preserved: AF, BC, DE, HL
print_regs:
call print_af
call print_bc
call print_de
call print_hl
call print_newline
ret
print_a:
push af
print_a_:
call print_hex
ld a,' '
call print_char_nocrc
pop af
ret
print_af:
push af
call print_hex
pop af
print_f:
push bc
push af
pop bc
call print_c
pop bc
ret
print_b:
push af
ld a,b
jr print_a_
print_c:
push af
ld a,c
jr print_a_
print_d:
push af
ld a,d
jr print_a_
print_e:
push af
ld a,e
jr print_a_
print_h:
push af
ld a,h
jr print_a_
print_l:
push af
ld a,l
jr print_a_
print_bc:
push af
push bc
print_bc_:
ld a,b
call print_hex
ld a,c
pop bc
jr print_a_
print_de:
push af
push bc
ld b,d
ld c,e
jr print_bc_
print_hl:
push af
push bc
ld b,h
ld c,l
jr print_bc_
; Prints A as two hex chars and updates checksum
; Preserved: BC, DE, HL
print_hex:
call update_crc
print_hex_nocrc:
push af
swap a
call +
pop af
+ and $0F
cp 10
jr c,+
add 7
+ add '0'
jp print_char_nocrc
; Prints char_nz if Z flag is clear,
; char_z if Z flag is set.
; Preserved: AF, BC, DE, HL
.macro print_nz ARGS char_nz, char_z
push af
ld a,char_nz
jr nz,print_nz\@
ld a,char_z
print_nz\@:
call print_char
pop af
.endm
; Prints char_nc if C flag is clear,
; char_c if C flag is set.
; Preserved: AF, BC, DE, HL
.macro print_nc ARGS char_nc, char_c
push af
ld a,char_nc
jr nz,print_nc\@
ld a,char_c
print_nc\@:
call print_char
pop af
.endm
; Prints A as 2 decimal digits
; Preserved: AF, BC, DE, HL
print_dec2:
push af
push bc
jr +
; Prints A as 1-3 digit decimal value
; Preserved: AF, BC, DE, HL
print_dec:
push af
push bc
cp 10
jr c,++
ld c,100
cp c
call nc,@digit
+ ld c,10
call @digit
++ add '0'
call print_char
pop bc
pop af
ret
@digit:
ld b,'0'-1
- inc b
sub c
jr nc,-
add c
ld c,a
ld a,b
call print_char
ld a,c
ret

View File

@ -0,0 +1,77 @@
; Main printing routine that checksums and
; prints to output device
; Character that does equivalent of print_newline
.define newline 10
; Prints char without updating checksum
; Preserved: BC, DE, HL
;print_char_nocrc (defined by user)
; Prints character and updates checksum UNLESS
; it's a newline.
; Preserved: AF, BC, DE, HL
print_char:
push af
cp newline
call nz,update_crc
call print_char_nocrc
pop af
ret
; Prints space. Does NOT update checksum.
; Preserved: AF, BC, DE, HL
print_space:
push af
ld a,' '
call print_char_nocrc
pop af
ret
; Advances to next line. Does NOT update checksum.
; Preserved: AF, BC, DE, HL
print_newline:
push af
ld a,newline
call print_char_nocrc
pop af
ret
; Prints immediate string
; Preserved: AF, BC, DE, HL
.macro print_str ; string,string2
push hl
call print_str_
.byte \1
.if NARGS > 1
.byte \2
.endif
.if NARGS > 2
.byte \3
.endif
.byte 0
pop hl
.endm
print_str_:
pop hl
call print_str_hl
jp hl
; Prints zero-terminated string pointed to by HL.
; On return, HL points to byte AFTER zero terminator.
; Preserved: AF, BC, DE
print_str_hl:
push af
jr +
- call print_char
+ ldi a,(hl)
or a
jr nz,-
pop af
ret

View File

@ -0,0 +1,261 @@
; Common routines and runtime
.define RUNTIME_INCLUDED 1
; A few bytes of RAM that aren't cleared
.define nv_ram_base $D800
.define nv_ram nv_ram_base
; Address of next normal variable
.define bss_base nv_ram_base+$80
.define bss bss_base
; Address of next direct-page ($FFxx) variable
.define dp_base $FF80
.define dp dp_base
; Top of stack
.define std_stack $DFFF+1
; Final exit result byte is written here
.define final_result $A000
; Text output is written here as zero-terminated string
.define text_out_base $A004
; DMG/CGB hardware identifier
.define gb_id_cgb $10 ; mask for testing CGB bit
.define gb_id_devcart $04 ; mask for testing "on devcart" bit
.define gb_id nv_ram
.redefine nv_ram nv_ram+1
; Copies C*$100 bytes from HL to $C000, then jumps to it.
; A is preserved for jumped-to code.
copy_to_wram_then_run:
ld b,a
ld de,$C000
- ld a,(hl+)
ld (de),a
inc e
jr nz,-
inc d
dec c
jr nz,-
ld a,b
jp $C000
.ifndef RST_OFFSET
.define RST_OFFSET 0
.endif
.ifndef CUSTOM_RESET
reset:
di
; Run code from $C000, as is done on devcart. This
; ensures minimal difference in how it behaves.
ld hl,$4000
ld c,$14
jp copy_to_wram_then_run
.bank 1 slot 1
.org 0
jp std_reset
.endif
; returnOrg puts this code AFTER user code.
.section "runtime" returnOrg
; Catch user code running off end
jp internal_error
; Common routines
.include "gb.inc"
.include "macros.inc"
.include "delay.s"
.include "crc.s"
.include "printing.s"
.include "numbers.s"
.include "testing.s"
; Sets up hardware and runs main
std_reset:
; Init hardware
di
ld sp,std_stack
; Save DMG/CGB id
ld (gb_id),a
; Clear memory except very top of stack
ld bc,std_stack-bss_base - 2
ld hl,bss_base
call clear_mem
ld bc,$FFFF-dp_base
ld hl,dp_base
call clear_mem
; Init hardware
wreg TAC,$00
wreg IF,$00
wreg IE,$00
wreg NR52,0 ; sound off
wreg NR52,$80 ; sound on
wreg NR51,$FF ; mono
wreg NR50,$77 ; volume
call init_runtime
call init_text_out
call console_init
call init_testing
.ifdef TEST_NAME
print_str TEST_NAME,newline,newline
.endif
call reset_crc ; in case init_runtime prints anything
delay_msec 250
; Run user code
call main
; Default is to successful exit
ld a,0
jp exit
; Exits code and reports value of A
exit:
ld sp,std_stack
push af
call +
call console_show
pop af
call play_byte
jp post_exit
+ push af
call print_newline
pop af
; Report exit status
cp 1
; 0: ""
ret c
; 1: "Failed"
jr nz,+
print_str "Failed",newline
ret
; n: "Failed #n"
+ print_str "Failed #"
call print_dec
call print_newline
ret
; Clears BC bytes starting at HL
clear_mem:
; If C>0, increment B
dec bc
inc c
inc b
ld a,0
- ld (hl+),a
dec c
jr nz,-
dec b
jr nz,-
ret
; Reports internal error and exits with code 255
internal_error:
print_str "Internal error"
ld a,255
jp exit
; build_devcart and build_multi customize this
.ifndef CUSTOM_PRINT
.define text_out_addr bss+0
.redefine bss bss+2
; Initializes text output to cartridge RAM
init_text_out:
; Enable cartridge RAM and set text output pointer
setb RAMEN,$0A
setw text_out_addr,text_out_base
setb text_out_base-3,$DE
setb text_out_base-2,$B0
setb text_out_base-1,$61
setb text_out_base,0
setb final_result,$80
ret
; Appends character to text output string
; Preserved: AF, BC, DE, HL
write_text_out:
push hl
push af
ld a,(text_out_addr)
ld l,a
ld a,(text_out_addr+1)
ld h,a
inc hl
ld (hl),0
ld a,l
ld (text_out_addr),a
ld a,h
ld (text_out_addr+1),a
dec hl
pop af
ld (hl),a
pop hl
ret
print_char_nocrc:
call write_text_out
jp console_print
.endif
; only build_rom uses console
.ifdef NEED_CONSOLE
.include "console.s"
.else
console_init:
console_print:
console_flush:
console_normal:
console_inverse:
console_show:
console_set_mode:
ret
.endif
; build_devcart and build_multi need to customize this
.ifndef CUSTOM_EXIT
post_exit:
ld (final_result),a
forever:
wreg NR52,0 ; sound off
- jr -
.endif
.macro def_rst ARGS addr
.bank 0 slot 0
.org addr+RST_OFFSET
.endm

View File

@ -0,0 +1,195 @@
; Diagnostic and testing utilities
.define test_code bss+0
.define test_name bss+1
.redefine bss bss+3
; Sets test code and optional error text.
; Takes multiple strings due to wla's idiotic
; default limit of 63 chars per string.
; Preserved: AF, BC, DE, HL
.macro set_test ; code[,text[,text2[,text3]]]
push hl
call set_test_
jr @set_test\@
.byte \1
.if NARGS > 1
.byte \2
.endif
.if NARGS > 2
.byte \3
.endif
.if NARGS > 3
.byte \4
.endif
.byte 0
@set_test\@:
pop hl
.endm
set_test_:
pop hl
push hl
push af
inc hl
inc hl
ldi a,(hl)
ld (test_code),a
ld a,l
ld (test_name),a
ld a,h
ld (test_name+1),a
pop af
ret
; Initializes testing module
init_testing:
set_test $FF
call init_crc
ret
; Reports "Passed", then exits with code 0
tests_passed:
call print_newline
print_str "Passed"
ld a,0
jp exit
; Reports "Done" if set_test has never been used,
; "Passed" if set_test 0 was last used, or
; failure if set_test n was last used.
tests_done:
ld a,(test_code)
inc a
jr z,+
dec a
jr z,tests_passed
jr test_failed
+ print_str "Done"
ld a,0
jp exit
; Reports current error text and exits with result code
test_failed:
ld a,(test_name)
ld l,a
ld a,(test_name+1)
ld h,a
ld a,(hl)
or a
jr z,+
call print_newline
call print_str_hl
call print_newline
+
ld a,(test_code)
cp $FF ; if a = $FF then a = 1
jr nz,+
ld a,1
+ jp exit
; Prints checksum as 8-character hex value
; Preserved: AF, BC, DE, HL
print_crc:
push af
; Must read checksum entirely before printing,
; since printing updates it.
lda checksum
cpl
push af
lda checksum+1
cpl
push af
lda checksum+2
cpl
push af
lda checksum+3
cpl
call print_hex
pop af
call print_hex
pop af
call print_hex
pop af
call print_a
pop af
ret
; If checksum doesn't match expected, reports failed test.
; Passing 0 just prints checksum. Clears checksum afterwards.
.macro check_crc ARGS crc
.if crc == 0
call print_newline
call print_crc
.else
ld bc,(crc >> 16) ~ $FFFF
ld de,(crc & $FFFF) ~ $FFFF
call check_crc_
.endif
.endm
; Checks CRC, differing based on DMG or CGB build
.macro check_crc_dmg_cgb ARGS dmg, cgb
.ifdef REQUIRE_DMG
check_crc dmg
.else
.ifdef REQUIRE_CGB
check_crc cgb
.else
.printt "CGB or DMG must be specified"
.fail
.endif
.endif
.endm
check_crc_:
lda checksum+0
cp e
jr nz,+
lda checksum+1
cp d
jr nz,+
lda checksum+2
cp c
jr nz,+
lda checksum+3
cp b
jr nz,+
jp reset_crc
+ call print_crc
jp test_failed
; Updates checksum with bytes from addr to addr+size-1
.macro checksum_mem ARGS addr,size
ld hl,addr
ld bc,size
call checksum_mem_
.endm
checksum_mem_:
- ldi a,(hl)
call update_crc
dec bc
ld a,b
or c
jr nz,-
ret

View File

@ -0,0 +1,2 @@
[objects]
test.o

View File

@ -0,0 +1,82 @@
Game Boy Tests Source Code
--------------------------
Building with wla-dx
--------------------
To assemble a test ROM with wla-dx, use the following commands:
wla -o source_filename_here.s test.o
wlalink linkfile test.gb
To assemble as a GBS music file:
wla -o source_filename_here.s test.o -DBUILD_GBS
wlalink linkfile test.gbs
Note that some tests might only work when built as a ROM or GBS file,
but not both.
Some tests might include a ROM/GBS that has all the tests combined.
Building such a multi-test is complex and the necessary files aren't
included.
Framework
---------
Each test is in a single source file, and makes use of several library
source files from common/. This framework provides common services and
reduces code to only that which performs the actual test. Virtually all
tests include "shell.inc" at the beginning, which sets things up and
includes all the appropriate library files.
The reset handler does minimal GB hardware initialization, clears RAM,
sets up the text console, then runs main. Main can exit by returning or
jumping to "exit" with an error code in A. Exit reports the code then
goes into an infinite loop. If the code is 0, it doesn't do anything,
otherwise it reports the code. Code 1 is reported as "Failed", and the
rest as "Error <code>".
The default is to build a ROM. Defining BUILD_GBS will build as an GBS.
The other build types aren't supported due to their complexity. I load
the code into RAM at $C000 since my devcart requires it, and I don't
want the normal ROM to differ in any way from what I've tested. This
also allows easy self-modifying code.
Several routines are available to print values and text to the console.
Most update a running CRC-32 checksum which can be checked with
check_crc, allowing ALL the output to be checked very easily. If the
checksum doesn't match, it is printed, so you can run the code on a GB
and paste the correct checksum into your code.
Macros
------
Some macros are used to make common operations more convenient. The left
is equivalent to the right:
Macro Equivalent
-------------------------------------
lda addr ldh a,(addr-$FF00)
sta addr ldh (addr-$FF00),a
wreg addr,data ld a,data
ldh (addr-$FF00),a
setb ld a,data
ld (addr),a
setw setb addr+0,<data
setb addr+1,>data
for_loop routine,begin,end,step
calls routine with A set to successive values
loop_n_times routine,count
calls routine with A from 0 to count-1
print_str "str" prints string
--
Shay Green <gblargg@gmail.com>

View File

@ -0,0 +1,27 @@
; Included at beginning of all programs
; that use standard shell
; Get include files from common/
.incdir "common"
; Sub-test in a multi-test ROM
.ifdef BUILD_MULTI
.include "build_multi.s"
.else
; GBS music file
.ifdef BUILD_GBS
.include "build_gbs.s"
.endif
; Devcart
.ifdef BUILD_DEVCART
.include "build_devcart.s"
.endif
; GB ROM (default)
.ifndef RUNTIME_INCLUDED
.include "build_rom.s"
.endif
.endif ; .ifdef BUILD_MULTI

Binary file not shown.

View File

@ -0,0 +1,119 @@
Game Boy CPU Instruction Behavior Test
--------------------------------------
This ROM tests the behavior of all CPU instructions except STOP and the
11 illegal opcodes. The tests are fairly thorough, running instructions
with boundary data and verifying both the result and that other
registers are not modified. Instructions which perform the same
operation on different registers are each tested just as thoroughly, in
case an emulator implements each independently. Some sub-tests take half
minute to complete.
Failed instructions are listed as
[CB] opcode
Some errors cannot of course be diagnosed properly, since the test
framework itself relies on basic instruction behavior being correct.
Internal operation
------------------
The main tests use a framework that runs each instruction in a loop,
varying the register values on input and examining them on output.
Rather than keep a table of correct values, it simply calculates a
CRC-32 checksum of all the output, then compares this with the correct
value. Instructions are divided into several groups, each with a
different set of input values suited for their behavior; for example,
the bit test instructions are fed $01, $02, $04 ... $40, $80, to ensure
each bit is handled properly, while the arithmetic instructions are fed
$01, $0F, $10, $7F, $FF, to exercise carry and half-carry. A few
instructions require a custom test due to their uniqueness.
Multi-ROM
---------
In the main directory is a single ROM which runs all the tests. It
prints a test's number, runs the test, then "ok" if it passes, otherwise
a failure code. Once all tests have completed it either reports that all
tests passed, or prints the number of failed tests. Finally, it makes
several beeps. If a test fails, it can be run on its own by finding the
corresponding ROM in individual/.
Ths compact format on screen is to avoid having the results scroll off
the top, so the test can be started and allowed to run without having to
constantly monitor the display.
Currently there is no well-defined way for an emulator test rig to
programatically find the result of the test; contact me if you're trying
to do completely automated testing of your emulator. One simple approach
is to take a screenshot after all tests have run, or even just a
checksum of one, and compare this with a previous run.
Failure codes
-------------
Failed tests may print a failure code, and also short description of the
problem. For more information about a failure code, look in the
corresponding source file in source/; the point in the code where
"set_test n" occurs is where that failure code will be generated.
Failure code 1 is a general failure of the test; any further information
will be printed.
Note that once a sub-test fails, no further tests for that file are run.
Console output
--------------
Information is printed on screen in a way that needs only minimum LCD
support, and won't hang if LCD output isn't supported at all.
Specifically, while polling LY to wait for vblank, it will time out if
it takes too long, so LY always reading back as the same value won't
hang the test. It's also OK if scrolling isn't supported; in this case,
text will appear starting at the top of the screen.
Everything printed on screen is also sent to the game link port by
writing the character to SB, then writing $81 to SC. This is useful for
tests which print lots of information that scrolls off screen.
Source code
-----------
Source code is included for all tests, in source/. It can be used to
build the individual test ROMs. Code for the multi test isn't included
due to the complexity of putting everything together.
Code is written for the wla-dx assembler. To assemble a particular test,
execute
wla -o "source_filename.s" test.o
wlalink linkfile test.gb
Test code uses a common shell framework contained in common/.
Internal framework operation
----------------------------
Tests use a common framework for setting things up, reporting results,
and ending. All files first include "shell.inc", which sets up the ROM
header and shell code, and includes other commonly-used modules.
One oddity is that test code is first copied to internal RAM at $D000,
then executed there. This allows self-modification, and ensures the code
is executed the same way it is on my devcart, which doesn't have a
rewritable ROM as most do.
Some macros are used to simplify common tasks:
Macro Behavior
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
wreg addr,data Writes data to addr using LDH
lda addr Loads byte from addr into A using LDH
sta addr Stores A at addr using LDH
delay n Delays n cycles, where NOP = 1 cycle
delay_msec n Delays n milliseconds
set_test n,"Cause" Sets failure code and optional string
Routines and macros are documented where they are defined.
--
Shay Green <gblargg@gmail.com>

View File

@ -0,0 +1,78 @@
; Tests instructions that don't fit template
.include "shell.inc"
main:
set_test 2,"JR negative"
ld a,0
jp jr_neg
inc a
- inc a
inc a
cp 2
jp nz,test_failed
jp +
jr_neg:
jr -
+
set_test 3,"JR positive"
ld a,0
jr +
inc a
+ inc a
inc a
cp 2
jp nz,test_failed
set_test 4,"LD PC,HL"
ld hl,+
ld a,0
ld pc,hl
inc a
+ inc a
inc a
cp 2
jp nz,test_failed
set_test 5,"POP AF"
ld bc,$1200
- push bc
pop af
push af
pop de
ld a,c
and $F0
cp e
jp nz,test_failed
inc b
inc c
jr nz,-
set_test 6,"DAA"
; Test all combinations of A and flags (256*16 total)
ld de,0
- push de
pop af
daa
push af
call update_crc
pop hl
ld a,l
call update_crc
inc d
jr nz,-
ld a,e
add $10
ld e,a
jr nz,-
check_crc $6A9F8D8A
jp tests_passed

View File

@ -0,0 +1,73 @@
; Tests DI, EI, and HALT (STOP proved untestable)
.include "shell.inc"
main:
wreg IE,$04
set_test 2,"EI"
ei
ld bc,0
push bc
pop bc
inc b
wreg IF,$04
interrupt_addr:
dec b
jp nz,test_failed
ld hl,sp-2
ldi a,(hl)
cp <interrupt_addr
jp nz,test_failed
ld a,(hl)
cp >interrupt_addr
jp nz,test_failed
lda IF
and $04
jp nz,test_failed
set_test 3,"DI"
di
ld bc,0
push bc
pop bc
wreg IF,$04
ld hl,sp-2
ldi a,(hl)
or (hl)
jp nz,test_failed
lda IF
and $04
jp z,test_failed
set_test 4,"Timer doesn't work"
wreg TAC,$05
wreg TIMA,0
wreg IF,0
delay 500
lda IF
delay 500
and $04
jp nz,test_failed
delay 500
lda IF
and $04
jp z,test_failed
pop af
set_test 5,"HALT"
wreg TAC,$05
wreg TIMA,0
wreg IF,0
halt ; timer interrupt will exit halt
nop ; avoids DMG bug
lda IF
and $04
jp z,test_failed
jp tests_passed
.bank 0 slot 0
.org $50
inc a
ret

View File

@ -0,0 +1,102 @@
; Tests SP/HL instructions
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
.byte $33,0,0 ; INC SP
.byte $3B,0,0 ; DEC SP
.byte $39,0,0 ; ADD HL,SP
.byte $F9,0,0 ; LD SP,HL
.byte $E8,$01,0 ; ADD SP,1
.byte $E8,$FF,0 ; ADD SP,-1
.byte $F8,$01,0 ; LD HL,SP+1
.byte $F8,$FF,0 ; LD HL,SP-1
instrs_end:
test_instr:
; C = flags register
ld c,$00
call test
ld c,$F0
call test
ret
test:
; Go through each value for HL
ld hl,values
hl_loop:
ld e,(hl)
inc hl
ld d,(hl)
inc hl
push hl
; Go through each value for SP
ld hl,values
values_loop:
push bc
push de
push hl
push bc
pop af
; Switch stack
ld (temp),sp
ld a,(hl+)
ld h,(hl)
ld l,a
; call print_regs
ld sp,hl
; Set registers
ld h,d
ld l,e
ld a,$12
ld bc,$5691
ld de,$9ABC
jp instr
instr_done:
; Save new SP and switch to yet another stack
ld (temp+2),sp
ld sp,$DF70
call checksum_af_bc_de_hl
; Checksum SP
ld a,(temp+2)
call update_crc_fast
ld a,(temp+3)
call update_crc_fast
ldsp temp
pop hl
pop de
pop bc
inc hl
inc hl
ld a,l
cp <values_end
jr nz,values_loop
pop hl
ld a,l
cp <values_end
jr nz,hl_loop
ret
values:
.word $0000,$0001,$000F,$0010,$001F,$007F,$0080,$00FF
.word $0100,$0F00,$1F00,$1000,$7FFF,$8000,$FFFF
values_end:
.word $0000,$0001,$000F,$0010,$001F,$007F,$0080,$00FF
.word $0100,$0F00,$1F00,$1000,$7FFF,$8000,$FFFF
checksums:
.byte $BC,$F4,$CD,$8C,$C7,$5E,$89,$E5,$36,$65,$21,$55,$D6,$6A,$2A,$FF
.byte $EB,$34,$37,$B9,$08,$5F,$22,$13,$B6,$2A,$37,$C3,$72,$43,$5C,$4D

View File

@ -0,0 +1,88 @@
; Tests immediate instructions
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
.byte $36,0,0 ; LD (HL),$00
.byte $06,0,0 ; LD B,$00
.byte $0E,0,0 ; LD C,$00
.byte $16,0,0 ; LD D,$00
.byte $1E,0,0 ; LD E,$00
.byte $26,0,0 ; LD H,$00
.byte $2E,0,0 ; LD L,$00
.byte $3E,0,0 ; LD A,$00
.byte $F6,0,0 ; OR $00
.byte $FE,0,0 ; CP $00
.byte $C6,0,0 ; ADD $00
.byte $CE,0,0 ; ADC $00
.byte $D6,0,0 ; SUB $00
.byte $DE,0,0 ; SBC $00
.byte $E6,0,0 ; AND $00
.byte $EE,0,0 ; XOR $00
instrs_end:
test_instr:
ld c,$00
call test
ld c,$10
call test
ld c,$E0
call test
ld c,$F0
call test
ret
test:
; Go through each value for A
ld hl,values
a_loop:
ld b,(hl)
push hl
; Go through each value for immediate data
ld hl,values
values_loop:
push bc
push hl
; Set registers
push bc
ld a,(hl)
ld (instr+1),a
ld bc,$1234
ld de,$5678
ld hl,rp_temp
pop af
; call print_regs
jp instr
instr_done:
; Checksum registers and (hl)
call checksum_af_bc_de_hl
ld a,(rp_temp)
call update_crc_fast
pop hl
pop bc
inc hl
ld a,l
cp <values_end
jr nz,values_loop
pop hl
inc hl
ld a,l
cp <values_end
jr nz,a_loop
ret
values:
.byte $00,$01,$0F,$10,$1F,$7F,$80,$F0,$FF
values_end:
checksums:
.byte $7F,$7F,$05,$B7,$85,$82,$94,$B6,$D8,$0A,$D6,$F5,$44,$8C,$37,$2A,$FB,$46,$05,$FA,$BD,$2F,$9E,$C1,$5A,$56,$2A,$DA,$D0,$EE,$14,$BA,$EA,$42,$36,$D2,$87,$28,$AB,$30,$4D,$A2,$63,$C6,$34,$4E,$55,$08,$9B,$1C,$97,$0E,$49,$F8,$73,$D4,$86,$C7,$DC,$C6,$03,$BF,$43,$21,

View File

@ -0,0 +1,98 @@
; Tests BC/DE/HL arithmetic
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
.byte $0B,0,0 ; DEC BC
.byte $1B,0,0 ; DEC DE
.byte $2B,0,0 ; DEC HL
.byte $03,0,0 ; INC BC
.byte $13,0,0 ; INC DE
.byte $23,0,0 ; INC HL
.byte $09,0,0 ; ADD HL,BC
.byte $19,0,0 ; ADD HL,DE
.byte $29,0,0 ; ADD HL,HL
instrs_end:
test_instr:
ld c,$00
call test
ld c,$10
call test
ld c,$E0
call test
ld c,$F0
call test
ret
test:
; Go through each value for HL
ld hl,values
hl_loop:
ld e,(hl)
inc hl
ld d,(hl)
inc hl
push hl
; Go through each value for BC, DE, A
ld hl,values
values_loop:
push bc
push de
push hl
push de
push bc
; BC
ld c,(hl)
inc hl
ld b,(hl)
inc hl
; DE
ld e,(hl)
inc hl
ld d,(hl)
inc hl
; HL, AF
pop af
ld a,(hl)
pop hl
; call print_regs
jp instr
instr_done:
; Checksum registers
call checksum_af_bc_de_hl
pop hl
pop de
pop bc
inc hl
inc hl
ld a,l
cp <values_end
jr nz,values_loop
pop hl
ld a,l
cp <values_end
jr nz,hl_loop
ret
values:
.word $0000,$0001,$000F,$0010,$001F,$007F,$0080,$00FF
.word $0100,$0F00,$1F00,$1000,$7FFF,$8000,$FFFF
values_end:
.word $0000,$0001,$000F,$0010,$001F,$007F,$0080,$00FF
.word $0100,$0F00,$1F00,$1000,$7FFF,$8000,$FFFF
checksums:
.byte $C0,$A1,$36,$A3,$BE,$15,$B8,$2B,$9F,$93,$C6,$C2,$86,$C0,$07,$81,$0F,$75,$35,$38,$6B,$C7,$0A,$1B,$06,$68,$4B,$42,$64,$B4,$8C,$18,$FB,$6C,$31,$94,

View File

@ -0,0 +1,115 @@
; Tests LD r,r ($40-$7F)
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
.byte $40,0,0 ; LD B,B
.byte $41,0,0 ; LD B,C
.byte $42,0,0 ; LD B,D
.byte $43,0,0 ; LD B,E
.byte $44,0,0 ; LD B,H
.byte $45,0,0 ; LD B,L
.byte $46,0,0 ; LD B,(HL)
.byte $47,0,0 ; LD B,A
.byte $48,0,0 ; LD C,B
.byte $49,0,0 ; LD C,C
.byte $4A,0,0 ; LD C,D
.byte $4B,0,0 ; LD C,E
.byte $4C,0,0 ; LD C,H
.byte $4D,0,0 ; LD C,L
.byte $4E,0,0 ; LD C,(HL)
.byte $4F,0,0 ; LD C,A
.byte $50,0,0 ; LD D,B
.byte $51,0,0 ; LD D,C
.byte $52,0,0 ; LD D,D
.byte $53,0,0 ; LD D,E
.byte $54,0,0 ; LD D,H
.byte $55,0,0 ; LD D,L
.byte $56,0,0 ; LD D,(HL)
.byte $57,0,0 ; LD D,A
.byte $58,0,0 ; LD E,B
.byte $59,0,0 ; LD E,C
.byte $5A,0,0 ; LD E,D
.byte $5B,0,0 ; LD E,E
.byte $5C,0,0 ; LD E,H
.byte $5D,0,0 ; LD E,L
.byte $5E,0,0 ; LD E,(HL)
.byte $5F,0,0 ; LD E,A
.byte $60,0,0 ; LD H,B
.byte $61,0,0 ; LD H,C
.byte $62,0,0 ; LD H,D
.byte $63,0,0 ; LD H,E
.byte $64,0,0 ; LD H,H
.byte $65,0,0 ; LD H,L
.byte $66,0,0 ; LD H,(HL)
.byte $67,0,0 ; LD H,A
.byte $68,0,0 ; LD L,B
.byte $69,0,0 ; LD L,C
.byte $6A,0,0 ; LD L,D
.byte $6B,0,0 ; LD L,E
.byte $6C,0,0 ; LD L,H
.byte $6D,0,0 ; LD L,L
.byte $6E,0,0 ; LD L,(HL)
.byte $6F,0,0 ; LD L,A
.byte $70,0,0 ; LD (HL),B
.byte $71,0,0 ; LD (HL),C
.byte $72,0,0 ; LD (HL),D
.byte $73,0,0 ; LD (HL),E
.byte $74,0,0 ; LD (HL),H
.byte $75,0,0 ; LD (HL),L
.byte $77,0,0 ; LD (HL),A
.byte $78,0,0 ; LD A,B
.byte $79,0,0 ; LD A,C
.byte $7A,0,0 ; LD A,D
.byte $7B,0,0 ; LD A,E
.byte $7C,0,0 ; LD A,H
.byte $7D,0,0 ; LD A,L
.byte $7E,0,0 ; LD A,(HL)
.byte $7F,0,0 ; LD A,A
instrs_end:
test_instr:
ld c,$00
call test
ld c,$10
call test
ld c,$E0
call test
ld c,$F0
call test
ret
test:
; Put different value in each register and (hl_temp)
ld b,$BC
push bc
ld a,$DE
ld (rp_temp),a
ld a,$12
ld bc,$3456
ld de,$789A
ld hl,rp_temp ; (HL) points to RAM
pop af
; call print_regs
jp instr
instr_done:
; Checksum registers and (HL)
call checksum_af_bc_de_hl
ld a,(rp_temp)
call update_crc_fast
ret
checksums:
.byte $40,$3A,$AF,$06,$B6,$CB,$B2,$AB,$6F,$EF,$71,$9B,$75,$E3,$6C,$B9,$34,$FB,$26,$B7,$5A,$B9,$2F,$CE,$34,$FB,$26,$B7,$C2,$0A,$3B,$1A,$2A,$8A,$D6,$7C,$40,$3A,$AF,$06,$AF,$0A,$74,$70,$19,$A9,$6E,$6F,$11,$DA,$FE,$FE,$18,$10,$04,$2B,$11,$DA,$FE,$FE,$7B,$6A,$87,$84,$8B,$87,$34,$12,$00,$45,$DE,$01,$40,$3A,$AF,$06,$93,$E2,$8F,$C6,$DD,$7D,$90,$32,$FF,$90,$1B,$A8,$DD,$7D,$90,$32,$56,$BF,$7A,$21,$23,$C0,$FA,$06,$3B,$1D,$A0,$80,$3F,$44,$1B,$9C,$40,$3A,$AF,$06,$56,$25,$85,$CD,$D7,$B1,$DB,$F9,$56,$25,$85,$CD,$4E,$F8,$DF,$4B,$F0,$C3,$F9,$18,$20,$0F,$F6,$91,$71,$69,$CE,$46,$F0,$A0,$03,$4D,$40,$3A,$AF,$06,$29,$47,$E2,$36,$40,$3A,$AF,$06,$90,$F6,$A0,$8F,$3D,$62,$26,$A9,$A4,$52,$C1,$75,$45,$ED,$75,$40,$8A,$4D,$63,$56,$AF,$BA,$2D,$FE,$40,$3A,$AF,$06,$AF,$BA,$2D,$FE,$36,$8A,$CA,$22,$34,$8D,$C2,$65,$1A,$DB,$FF,$54,$32,$C0,$E8,$55,$ED,$4A,$87,$2F,$40,$3A,$AF,$06,$9D,$BC,$81,$E6,$6E,$6C,$92,$37,$B1,$EC,$C3,$29,$1D,$C5,$9F,$A1,$59,$6F,$66,$CD,$B4,$FB,$FD,$74,$EC,$13,$F3,$8E,$70,$0C,$5F,$ED,$EC,$13,$F3,$8E,$40,$3A,$AF,$06,

View File

@ -0,0 +1,127 @@
; Tests branch instructions
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
; JR cond,skip
; INC A
; skip:
.byte $18,$01,$3C ; JR *+3
.byte $20,$01,$3C ; JR NZ,*+3
.byte $28,$01,$3C ; JR Z,*+3
.byte $30,$01,$3C ; JR NC,*+3
.byte $38,$01,$3C ; JR C,*+3
.byte $C2,<taken,>taken ; JP NZ,taken
.byte $C3,<taken,>taken ; JP taken
.byte $CA,<taken,>taken ; JP Z,taken
.byte $D2,<taken,>taken ; JP NC,taken
.byte $DA,<taken,>taken ; JP C,taken
.byte $C4,<taken,>taken ; CALL NZ,taken
.byte $CC,<taken,>taken ; CALL Z,taken
.byte $CD,<taken,>taken ; CALL taken
.byte $D4,<taken,>taken ; CALL NC,taken
.byte $DC,<taken,>taken ; CALL C,taken
; RET cond
; INC A
.byte $C0,$3C,0 ; RET NZ
.byte $C8,$3C,0 ; RET Z
.byte $C9,$3C,0 ; RET
.byte $D0,$3C,0 ; RET NC
.byte $D8,$3C,0 ; RET C
.byte $D9,$3C,0 ; RETI
; RST
; can only easily test this one on devcart
.byte $C7,0,0 ; RST $00
.ifndef BUILD_DEVCART
.byte $CF,0,0 ; RST $08
.byte $D7,0,0 ; RST $10
.byte $DF,0,0 ; RST $18
.byte $E7,0,0 ; RST $20
.byte $EF,0,0 ; RST $28
.byte $F7,0,0 ; RST $30
.byte $FF,0,0 ; RST $38
.endif
instrs_end:
test_instr:
wreg IE,0 ; disable interrupts, since RETI does EI
; Go through all 16 combinations of flags
ld bc,$1200
-
; Fill 4 bytes of new stack
ld a,$12
ld ($DF80-2),a
ld a,$34
ld ($DF80-3),a
ld a,$56
ld ($DF80-4),a
ld a,$78
ld ($DF80-5),a
; Set AF
push bc
pop af
; Switch to new stack
ld (temp),sp
ld sp,$DF80
; Set return address
ld de,instr+3
push de
jp instr
instr_done:
inc a
taken:
di ; RETI enables interrupts
; Save new SP and switch to yet another stack
ld (temp+2),sp
ld sp,$DF70
; Checksum A and SP
call update_crc_fast
ld a,(temp+2)
call update_crc_fast
ld a,(temp+3)
call update_crc_fast
; Checksum 4 bytes of stack
ld a,($DF80-2)
call update_crc_fast
ld a,($DF80-3)
call update_crc_fast
ld a,($DF80-4)
call update_crc_fast
ld a,($DF80-5)
call update_crc_fast
ldsp temp
ld a,c
add $10
ld c,a
jr nz,-
ret
checksums:
.byte $EC,$A4,$94,$79,$C4,$00,$96,$2C,$C4,$64,$90,$33,$77,$C7,$0A,$D4
.byte $77,$A3,$0C,$CB,$79,$E7,$7E,$AE,$DA,$DC,$03,$F7,$4F,$9F,$E9,$20
.byte $72,$12,$DA,$01,$44,$6A,$4D,$8F,$D1,$79,$30,$4C,$AA,$37,$F2,$6A
.byte $97,$EA,$56,$5F,$32,$28,$C7,$D1,$49,$66,$05,$F7,$80,$0F,$BA,$8E
.byte $41,$E2,$A4,$9A,$2D,$2D,$8C,$72,$A5,$13,$76,$A8,$64,$FE,$68,$BC
.byte $2D,$2D,$8C,$72,$50,$96,$24,$27,$50,$96,$24,$27,$50,$96,$24,$27
.byte $50,$96,$24,$27,$50,$96,$24,$27,$50,$96,$24,$27,$50,$96,$24,$27
.byte $50,$96,$24,$27
.include "multi_custom.s"

View File

@ -0,0 +1,110 @@
; Tests miscellaneous instructions
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
.byte $F0,$91,0 ; LDH A,($91)
.byte $E0,$91,0 ; LDH ($91),A
.byte $F2,$00,0 ; LDH A,(C)
.byte $E2,$00,0 ; LDH (C),A
.byte $FA,$91,$FF ; LD A,($FF91)
.byte $EA,$91,$FF ; LD ($FF91),A
.byte $08,$91,$FF ; LD ($FF91),SP
.byte $01,$23,$01 ; LD BC,$0123
.byte $11,$23,$01 ; LD DE,$0123
.byte $21,$23,$01 ; LD HL,$0123
.byte $31,$23,$01 ; LD SP,$0123
.byte $F5,0,0 ; PUSH AF
.byte $C5,0,0 ; PUSH BC
.byte $D5,0,0 ; PUSH DE
.byte $E5,0,0 ; PUSH HL
.byte $F1,0,0 ; POP AF
.byte $C1,0,0 ; POP BC
.byte $D1,0,0 ; POP DE
.byte $E1,0,0 ; POP HL
instrs_end:
test_instr:
; C = flags register
ld c,$00
call test
ld c,$10
call test
ld c,$E0
call test
ld c,$F0
call test
ret
test:
; Fill RAM
ld a,$FE
ld ($FF90),a
ld a,$DC
ld ($FF91),a
ld a,$BA
ld ($FF92),a
; Fill stack
ld a,$13
ld ($DF80),a
ld a,$57
ld ($DF80-1),a
ld a,$9B
ld ($DF80-2),a
ld a,$DF
ld ($DF80-3),a
; Set registers
ld b,$12
push bc
ld bc,$5691
ld de,$9ABC
ld hl,$DEF0
pop af
; Switch stack
ld (temp),sp
ld sp,$DF80-2
jp instr
instr_done:
; Save new SP and switch to another stack
ld (temp+2),sp
ld sp,$DF70
call checksum_af_bc_de_hl
; Checksum SP
ld a,(temp+2)
call update_crc_fast
ld a,(temp+3)
call update_crc_fast
; Checksum RAM
ld a,($FF90)
call update_crc_fast
ld a,($FF91)
call update_crc_fast
ld a,($FF92)
call update_crc_fast
; Checksum stack
ld a,($DF80)
call update_crc_fast
ld a,($DF80-1)
call update_crc_fast
ld a,($DF80-2)
call update_crc_fast
ld a,($DF80-3)
call update_crc_fast
; Restore SP
ldsp temp
ret
checksums:
.byte $4D,$FF,$15,$97,$6D,$A7,$35,$65,$4D,$FF,$15,$97,$6D,$A7,$35,$65,$4D,$FF,$15,$97,$6D,$A7,$35,$65,$AD,$FA,$5E,$41,$D0,$78,$79,$C1,$AF,$66,$99,$34,$0D,$E1,$97,$99,$6F,$D0,$6F,$5D,$C3,$1F,$A3,$8A,$C2,$F1,$9C,$F3,$C1,$C3,$DC,$78,$C0,$2D,$E3,$01,$8F,$C4,$0F,$44,$95,$22,$6A,$39,$61,$C5,$AB,$55,$FB,$DF,$2C,$52,

View File

@ -0,0 +1,269 @@
; Tests most register instructions.
; Takes 10 seconds.
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
.byte $00,0,0 ; NOP
.byte $2F,0,0 ; CPL
.byte $37,0,0 ; SCF
.byte $3F,0,0 ; CCF
.byte $B0,0,0 ; OR B
.byte $B1,0,0 ; OR C
.byte $B2,0,0 ; OR D
.byte $B3,0,0 ; OR E
.byte $B4,0,0 ; OR H
.byte $B5,0,0 ; OR L
.byte $B7,0,0 ; OR A
.byte $B8,0,0 ; CP B
.byte $B9,0,0 ; CP C
.byte $BA,0,0 ; CP D
.byte $BB,0,0 ; CP E
.byte $BC,0,0 ; CP H
.byte $BD,0,0 ; CP L
.byte $BF,0,0 ; CP A
.byte $80,0,0 ; ADD B
.byte $81,0,0 ; ADD C
.byte $82,0,0 ; ADD D
.byte $83,0,0 ; ADD E
.byte $84,0,0 ; ADD H
.byte $85,0,0 ; ADD L
.byte $87,0,0 ; ADD A
.byte $88,0,0 ; ADC B
.byte $89,0,0 ; ADC C
.byte $8A,0,0 ; ADC D
.byte $8B,0,0 ; ADC E
.byte $8C,0,0 ; ADC H
.byte $8D,0,0 ; ADC L
.byte $8F,0,0 ; ADC A
.byte $90,0,0 ; SUB B
.byte $91,0,0 ; SUB C
.byte $92,0,0 ; SUB D
.byte $93,0,0 ; SUB E
.byte $94,0,0 ; SUB H
.byte $95,0,0 ; SUB L
.byte $97,0,0 ; SUB A
.byte $98,0,0 ; SBC B
.byte $99,0,0 ; SBC C
.byte $9A,0,0 ; SBC D
.byte $9B,0,0 ; SBC E
.byte $9C,0,0 ; SBC H
.byte $9D,0,0 ; SBC L
.byte $9F,0,0 ; SBC A
.byte $A0,0,0 ; AND B
.byte $A1,0,0 ; AND C
.byte $A2,0,0 ; AND D
.byte $A3,0,0 ; AND E
.byte $A4,0,0 ; AND H
.byte $A5,0,0 ; AND L
.byte $A7,0,0 ; AND A
.byte $A8,0,0 ; XOR B
.byte $A9,0,0 ; XOR C
.byte $AA,0,0 ; XOR D
.byte $AB,0,0 ; XOR E
.byte $AC,0,0 ; XOR H
.byte $AD,0,0 ; XOR L
.byte $AF,0,0 ; XOR A
.byte $05,0,0 ; DEC B
.byte $0D,0,0 ; DEC C
.byte $15,0,0 ; DEC D
.byte $1D,0,0 ; DEC E
.byte $25,0,0 ; DEC H
.byte $2D,0,0 ; DEC L
.byte $3D,0,0 ; DEC A
.byte $04,0,0 ; INC B
.byte $0C,0,0 ; INC C
.byte $14,0,0 ; INC D
.byte $1C,0,0 ; INC E
.byte $24,0,0 ; INC H
.byte $2C,0,0 ; INC L
.byte $3C,0,0 ; INC A
.byte $07,0,0 ; RLCA
.byte $17,0,0 ; RLA
.byte $0F,0,0 ; RRCA
.byte $1F,0,0 ; RRA
.byte $CB,$00,0 ; RLC B
.byte $CB,$01,0 ; RLC C
.byte $CB,$02,0 ; RLC D
.byte $CB,$03,0 ; RLC E
.byte $CB,$04,0 ; RLC H
.byte $CB,$05,0 ; RLC L
.byte $CB,$07,0 ; RLC A
.byte $CB,$08,0 ; RRC B
.byte $CB,$09,0 ; RRC C
.byte $CB,$0A,0 ; RRC D
.byte $CB,$0B,0 ; RRC E
.byte $CB,$0C,0 ; RRC H
.byte $CB,$0D,0 ; RRC L
.byte $CB,$0F,0 ; RRC A
.byte $CB,$10,0 ; RL B
.byte $CB,$11,0 ; RL C
.byte $CB,$12,0 ; RL D
.byte $CB,$13,0 ; RL E
.byte $CB,$14,0 ; RL H
.byte $CB,$15,0 ; RL L
.byte $CB,$17,0 ; RL A
.byte $CB,$18,0 ; RR B
.byte $CB,$19,0 ; RR C
.byte $CB,$1A,0 ; RR D
.byte $CB,$1B,0 ; RR E
.byte $CB,$1C,0 ; RR H
.byte $CB,$1D,0 ; RR L
.byte $CB,$1F,0 ; RR A
.byte $CB,$20,0 ; SLA B
.byte $CB,$21,0 ; SLA C
.byte $CB,$22,0 ; SLA D
.byte $CB,$23,0 ; SLA E
.byte $CB,$24,0 ; SLA H
.byte $CB,$25,0 ; SLA L
.byte $CB,$27,0 ; SLA A
.byte $CB,$28,0 ; SRA B
.byte $CB,$29,0 ; SRA C
.byte $CB,$2A,0 ; SRA D
.byte $CB,$2B,0 ; SRA E
.byte $CB,$2C,0 ; SRA H
.byte $CB,$2D,0 ; SRA L
.byte $CB,$2F,0 ; SRA A
.byte $CB,$30,0 ; SWAP B
.byte $CB,$31,0 ; SWAP C
.byte $CB,$32,0 ; SWAP D
.byte $CB,$33,0 ; SWAP E
.byte $CB,$34,0 ; SWAP H
.byte $CB,$35,0 ; SWAP L
.byte $CB,$37,0 ; SWAP A
.byte $CB,$38,0 ; SRL B
.byte $CB,$39,0 ; SRL C
.byte $CB,$3A,0 ; SRL D
.byte $CB,$3B,0 ; SRL E
.byte $CB,$3C,0 ; SRL H
.byte $CB,$3D,0 ; SRL L
.byte $CB,$3F,0 ; SRL A
instrs_end:
test_instr:
ld c,$00
call test
ld c,$F0
call test
ret
test:
; Go through each value for A
ld hl,values
a_loop:
ld b,(hl)
push hl
; Go through each value for other registers
ld hl,values
values_loop:
push bc
push hl
push bc
; BC
ld a,(hl+)
ld b,a
ld a,(hl+)
ld c,a
; HL
ld a,(hl+)
ld d,a
ld a,(hl+)
ld e,a
push de
; DE
ld a,(hl+)
ld d,a
ld a,(hl+)
ld e,a
pop hl
pop af
; call print_regs
jp instr
instr_done:
; Checksum registers
call checksum_af_bc_de_hl
pop hl
pop bc
inc hl
ld a,l
cp <values_end
jr nz,values_loop
pop hl
inc hl
ld a,l
cp <values_end
jr nz,a_loop
ret
values:
.byte $00,$01,$0F,$10,$1F,$7F,$80,$F0,$FF
values_end:
.byte $00,$01,$0F,$10,$1F,$7F,$80,$F0,$FF
checksums:
.byte $7C,$55,$BD,$05,$BA,$C7,$AC,$D1,$74,$6D,$82,$4A,$0F,$06,$2A,$C5
.byte $FA,$97,$9B,$9D,$C3,$32,$A0,$78,$00,$C1,$9F,$69,$C0,$D1,$C2,$A1
.byte $55,$0D,$3F,$C8,$09,$7D,$97,$92,$CE,$66,$30,$56,$95,$F3,$01,$A1
.byte $5B,$97,$54,$4C,$56,$FC,$A0,$89,$42,$F8,$7B,$2A,$E6,$7C,$03,$40
.byte $45,$60,$C5,$A8,$B7,$BF,$B0,$EF,$A0,$7A,$1B,$4F,$FB,$22,$B4,$33
.byte $06,$3D,$B5,$C7,$3C,$A4,$D5,$23,$C1,$BE,$75,$8B,$E0,$9B,$98,$BB
.byte $0E,$75,$D9,$E6,$82,$A7,$E2,$66,$CD,$78,$4F,$E8,$8E,$D4,$2D,$3E
.byte $88,$5C,$58,$C7,$F9,$20,$5F,$B9,$A8,$E4,$CA,$5E,$C8,$DB,$88,$94
.byte $A3,$0D,$87,$60,$8B,$BA,$2B,$27,$41,$88,$83,$B1,$0A,$41,$9E,$D6
.byte $98,$8D,$19,$B7,$13,$C6,$D5,$BF,$83,$CE,$74,$9F,$00,$34,$07,$5E
.byte $F0,$E1,$1A,$68,$8F,$BA,$85,$A7,$A0,$46,$06,$A5,$75,$F9,$83,$48
.byte $12,$EF,$1B,$03,$C8,$FB,$79,$EA,$9B,$00,$6C,$A9,$0D,$5E,$CB,$57
.byte $41,$1B,$4B,$0C,$B2,$08,$D8,$E3,$43,$07,$E1,$93,$34,$73,$23,$C9
.byte $18,$2F,$38,$F9,$D1,$3B,$AB,$5A,$BF,$C6,$F8,$03,$50,$0C,$A4,$32
.byte $6B,$06,$7E,$FE,$ED,$8B,$D4,$15,$29,$46,$6D,$24,$6E,$5B,$15,$1A
.byte $32,$AE,$87,$B0,$DC,$20,$AC,$4B,$2B,$63,$60,$C7,$C1,$92,$75,$AA
.byte $6F,$CA,$17,$53,$5A,$C5,$78,$EA,$61,$01,$10,$83,$DD,$08,$D8,$78
.byte $CA,$0B,$F5,$1F,$92,$55,$08,$01,$7F,$EA,$CD,$9B,$2A,$AA,$73,$17
.byte $E0,$9F,$D0,$BA,$E7,$73,$72,$3D,$B7,$95,$2F,$3B,$A7,$78,$50,$36
.byte $81,$04,$5B,$9E,$9A,$DE,$A4,$DD,$21,$B2,$9B,$36,$9F,$D7,$C8,$32
.byte $48,$0E,$FC,$E5,$55,$C3,$53,$75,$A4,$ED,$A9,$E0,$9E,$78,$A7,$1D
.byte $B8,$F4,$7C,$D6,$90,$2A,$03,$87,$81,$D8,$D5,$90,$63,$02,$C4,$52
.byte $C2,$BE,$85,$B3,$32,$9A,$9E,$2D,$E3,$FB,$22,$47,$8E,$65,$08,$73
.byte $72,$5A,$73,$95,$ED,$EC,$59,$9D,$C8,$67,$68,$F1,$4B,$ED,$41,$D5
.byte $68,$39,$75,$F3,$FC,$09,$EF,$0D,$20,$2B,$43,$A3,$69,$AA,$89,$4F
.byte $84,$87,$7B,$58,$42,$0A,$56,$EF,$1B,$0E,$19,$CA,$6F,$1B,$F9,$17
.byte $EA,$B6,$4C,$B2,$1A,$C4,$C0,$B1,$E2,$B2,$45,$4E,$91,$0A,$8D,$AE
.byte $17,$31,$55,$A3,$1B,$69,$72,$D8,$03,$E9,$55,$8D,$87,$27,$36,$63
.byte $E6,$85,$12,$D1,$F2,$32,$97,$4D,$B5,$FA,$08,$A9,$97,$2A,$5A,$C2
.byte $FD,$2D,$A4,$27,$57,$7C,$EC,$BD,$CC,$67,$19,$21,$46,$D4,$CD,$D6
.byte $CB,$55,$D4,$E2,$9E,$F3,$32,$2E,$AA,$F8,$BB,$B3,$F6,$3A,$CC,$08
.byte $64,$8B,$C2,$5F,$58,$66,$AF,$67,$B3,$44,$2C,$66,$72,$E7,$3B,$3F
.byte $5B,$87,$0C,$17,$58,$E2,$B4,$A0,$70,$18,$81,$E6,$42,$56,$12,$CE
.byte $BB,$13,$46,$3C,$BE,$5A,$FB,$53

View File

@ -0,0 +1,315 @@
; Tests most register instructions.
; Takes 15 seconds.
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
.byte $CB,$40,0 ; BIT 0,B
.byte $CB,$41,0 ; BIT 0,C
.byte $CB,$42,0 ; BIT 0,D
.byte $CB,$43,0 ; BIT 0,E
.byte $CB,$44,0 ; BIT 0,H
.byte $CB,$45,0 ; BIT 0,L
.byte $CB,$47,0 ; BIT 0,A
.byte $CB,$48,0 ; BIT 1,B
.byte $CB,$49,0 ; BIT 1,C
.byte $CB,$4A,0 ; BIT 1,D
.byte $CB,$4B,0 ; BIT 1,E
.byte $CB,$4C,0 ; BIT 1,H
.byte $CB,$4D,0 ; BIT 1,L
.byte $CB,$4F,0 ; BIT 1,A
.byte $CB,$50,0 ; BIT 2,B
.byte $CB,$51,0 ; BIT 2,C
.byte $CB,$52,0 ; BIT 2,D
.byte $CB,$53,0 ; BIT 2,E
.byte $CB,$54,0 ; BIT 2,H
.byte $CB,$55,0 ; BIT 2,L
.byte $CB,$57,0 ; BIT 2,A
.byte $CB,$58,0 ; BIT 3,B
.byte $CB,$59,0 ; BIT 3,C
.byte $CB,$5A,0 ; BIT 3,D
.byte $CB,$5B,0 ; BIT 3,E
.byte $CB,$5C,0 ; BIT 3,H
.byte $CB,$5D,0 ; BIT 3,L
.byte $CB,$5F,0 ; BIT 3,A
.byte $CB,$60,0 ; BIT 4,B
.byte $CB,$61,0 ; BIT 4,C
.byte $CB,$62,0 ; BIT 4,D
.byte $CB,$63,0 ; BIT 4,E
.byte $CB,$64,0 ; BIT 4,H
.byte $CB,$65,0 ; BIT 4,L
.byte $CB,$67,0 ; BIT 4,A
.byte $CB,$68,0 ; BIT 5,B
.byte $CB,$69,0 ; BIT 5,C
.byte $CB,$6A,0 ; BIT 5,D
.byte $CB,$6B,0 ; BIT 5,E
.byte $CB,$6C,0 ; BIT 5,H
.byte $CB,$6D,0 ; BIT 5,L
.byte $CB,$6F,0 ; BIT 5,A
.byte $CB,$70,0 ; BIT 6,B
.byte $CB,$71,0 ; BIT 6,C
.byte $CB,$72,0 ; BIT 6,D
.byte $CB,$73,0 ; BIT 6,E
.byte $CB,$74,0 ; BIT 6,H
.byte $CB,$75,0 ; BIT 6,L
.byte $CB,$77,0 ; BIT 6,A
.byte $CB,$78,0 ; BIT 7,B
.byte $CB,$79,0 ; BIT 7,C
.byte $CB,$7A,0 ; BIT 7,D
.byte $CB,$7B,0 ; BIT 7,E
.byte $CB,$7C,0 ; BIT 7,H
.byte $CB,$7D,0 ; BIT 7,L
.byte $CB,$7F,0 ; BIT 7,A
.byte $CB,$80,0 ; RES 0,B
.byte $CB,$81,0 ; RES 0,C
.byte $CB,$82,0 ; RES 0,D
.byte $CB,$83,0 ; RES 0,E
.byte $CB,$84,0 ; RES 0,H
.byte $CB,$85,0 ; RES 0,L
.byte $CB,$87,0 ; RES 0,A
.byte $CB,$88,0 ; RES 1,B
.byte $CB,$89,0 ; RES 1,C
.byte $CB,$8A,0 ; RES 1,D
.byte $CB,$8B,0 ; RES 1,E
.byte $CB,$8C,0 ; RES 1,H
.byte $CB,$8D,0 ; RES 1,L
.byte $CB,$8F,0 ; RES 1,A
.byte $CB,$90,0 ; RES 2,B
.byte $CB,$91,0 ; RES 2,C
.byte $CB,$92,0 ; RES 2,D
.byte $CB,$93,0 ; RES 2,E
.byte $CB,$94,0 ; RES 2,H
.byte $CB,$95,0 ; RES 2,L
.byte $CB,$97,0 ; RES 2,A
.byte $CB,$98,0 ; RES 3,B
.byte $CB,$99,0 ; RES 3,C
.byte $CB,$9A,0 ; RES 3,D
.byte $CB,$9B,0 ; RES 3,E
.byte $CB,$9C,0 ; RES 3,H
.byte $CB,$9D,0 ; RES 3,L
.byte $CB,$9F,0 ; RES 3,A
.byte $CB,$A0,0 ; RES 4,B
.byte $CB,$A1,0 ; RES 4,C
.byte $CB,$A2,0 ; RES 4,D
.byte $CB,$A3,0 ; RES 4,E
.byte $CB,$A4,0 ; RES 4,H
.byte $CB,$A5,0 ; RES 4,L
.byte $CB,$A7,0 ; RES 4,A
.byte $CB,$A8,0 ; RES 5,B
.byte $CB,$A9,0 ; RES 5,C
.byte $CB,$AA,0 ; RES 5,D
.byte $CB,$AB,0 ; RES 5,E
.byte $CB,$AC,0 ; RES 5,H
.byte $CB,$AD,0 ; RES 5,L
.byte $CB,$AF,0 ; RES 5,A
.byte $CB,$B0,0 ; RES 6,B
.byte $CB,$B1,0 ; RES 6,C
.byte $CB,$B2,0 ; RES 6,D
.byte $CB,$B3,0 ; RES 6,E
.byte $CB,$B4,0 ; RES 6,H
.byte $CB,$B5,0 ; RES 6,L
.byte $CB,$B7,0 ; RES 6,A
.byte $CB,$B8,0 ; RES 7,B
.byte $CB,$B9,0 ; RES 7,C
.byte $CB,$BA,0 ; RES 7,D
.byte $CB,$BB,0 ; RES 7,E
.byte $CB,$BC,0 ; RES 7,H
.byte $CB,$BD,0 ; RES 7,L
.byte $CB,$BF,0 ; RES 7,A
.byte $CB,$C0,0 ; SET 0,B
.byte $CB,$C1,0 ; SET 0,C
.byte $CB,$C2,0 ; SET 0,D
.byte $CB,$C3,0 ; SET 0,E
.byte $CB,$C4,0 ; SET 0,H
.byte $CB,$C5,0 ; SET 0,L
.byte $CB,$C7,0 ; SET 0,A
.byte $CB,$C8,0 ; SET 1,B
.byte $CB,$C9,0 ; SET 1,C
.byte $CB,$CA,0 ; SET 1,D
.byte $CB,$CB,0 ; SET 1,E
.byte $CB,$CC,0 ; SET 1,H
.byte $CB,$CD,0 ; SET 1,L
.byte $CB,$CF,0 ; SET 1,A
.byte $CB,$D0,0 ; SET 2,B
.byte $CB,$D1,0 ; SET 2,C
.byte $CB,$D2,0 ; SET 2,D
.byte $CB,$D3,0 ; SET 2,E
.byte $CB,$D4,0 ; SET 2,H
.byte $CB,$D5,0 ; SET 2,L
.byte $CB,$D7,0 ; SET 2,A
.byte $CB,$D8,0 ; SET 3,B
.byte $CB,$D9,0 ; SET 3,C
.byte $CB,$DA,0 ; SET 3,D
.byte $CB,$DB,0 ; SET 3,E
.byte $CB,$DC,0 ; SET 3,H
.byte $CB,$DD,0 ; SET 3,L
.byte $CB,$DF,0 ; SET 3,A
.byte $CB,$E0,0 ; SET 4,B
.byte $CB,$E1,0 ; SET 4,C
.byte $CB,$E2,0 ; SET 4,D
.byte $CB,$E3,0 ; SET 4,E
.byte $CB,$E4,0 ; SET 4,H
.byte $CB,$E5,0 ; SET 4,L
.byte $CB,$E7,0 ; SET 4,A
.byte $CB,$E8,0 ; SET 5,B
.byte $CB,$E9,0 ; SET 5,C
.byte $CB,$EA,0 ; SET 5,D
.byte $CB,$EB,0 ; SET 5,E
.byte $CB,$EC,0 ; SET 5,H
.byte $CB,$ED,0 ; SET 5,L
.byte $CB,$EF,0 ; SET 5,A
.byte $CB,$F0,0 ; SET 6,B
.byte $CB,$F1,0 ; SET 6,C
.byte $CB,$F2,0 ; SET 6,D
.byte $CB,$F3,0 ; SET 6,E
.byte $CB,$F4,0 ; SET 6,H
.byte $CB,$F5,0 ; SET 6,L
.byte $CB,$F7,0 ; SET 6,A
.byte $CB,$F8,0 ; SET 7,B
.byte $CB,$F9,0 ; SET 7,C
.byte $CB,$FA,0 ; SET 7,D
.byte $CB,$FB,0 ; SET 7,E
.byte $CB,$FC,0 ; SET 7,H
.byte $CB,$FD,0 ; SET 7,L
.byte $CB,$FF,0 ; SET 7,A
instrs_end:
test_instr:
ld c,$00
call test
ld c,$F0
call test
ret
test:
; Go through each value for A
ld hl,values
a_loop:
ld b,(hl)
push hl
; Go through each value for other registers
ld hl,values
values_loop:
push bc
push hl
push bc
; BC
ld a,(hl+)
ld b,a
ld a,(hl+)
ld c,a
; HL
ld a,(hl+)
ld d,a
ld a,(hl+)
ld e,a
push de
; DE
ld a,(hl+)
ld d,a
ld a,(hl+)
ld e,a
pop hl
pop af
; call print_regs
jp instr
instr_done:
; Checksum registers
call checksum_af_bc_de_hl
pop hl
pop bc
inc hl
ld a,l
cp <values_end
jr nz,values_loop
pop hl
inc hl
ld a,l
cp <values_end
jr nz,a_loop
ret
values:
.byte $00,$01,$02,$04,$08,$10,$20,$40,$80,$FF
values_end:
.byte $00,$01,$02,$04,$08,$10,$20,$40,$80,$FF
checksums:
.byte $46,$51,$4A,$16,$D4,$18,$B2,$4E,$ED,$B5,$15,$EA,$74,$66,$66,$3E
.byte $C2,$F3,$7F,$6A,$63,$CA,$62,$21,$72,$1E,$E4,$83,$6A,$56,$41,$1D
.byte $91,$90,$DB,$38,$54,$0A,$6C,$24,$02,$9E,$EA,$5B,$6D,$A7,$CB,$80
.byte $B4,$0B,$F3,$0F,$40,$38,$75,$BB,$AF,$30,$2B,$E5,$BD,$97,$D0,$33
.byte $83,$CB,$FD,$0A,$BB,$21,$93,$95,$28,$2F,$A2,$F6,$1B,$5F,$47,$E5
.byte $A3,$2E,$39,$63,$6C,$E0,$02,$BB,$78,$F1,$BA,$CB,$2C,$9F,$49,$E0
.byte $6C,$E0,$02,$BB,$04,$28,$A9,$FD,$5E,$D7,$2E,$93,$1B,$78,$08,$00
.byte $83,$CB,$FD,$0A,$BB,$21,$93,$95,$69,$17,$20,$96,$C3,$B4,$B6,$51
.byte $C1,$4E,$C3,$05,$72,$D0,$25,$98,$44,$F0,$99,$B7,$B4,$0B,$F3,$0F
.byte $54,$0A,$6C,$24,$45,$10,$2B,$9D,$86,$3C,$DF,$27,$02,$9E,$EA,$5B
.byte $B7,$B6,$4F,$60,$70,$E0,$E1,$AA,$C2,$F3,$7F,$6A,$63,$CA,$62,$21
.byte $80,$76,$41,$65,$AA,$3B,$D4,$2C,$ED,$B5,$15,$EA,$74,$66,$66,$3E
.byte $AD,$FF,$A0,$43,$7B,$4C,$06,$A4,$15,$32,$EE,$44,$43,$A6,$68,$3B
.byte $6F,$5D,$BE,$D4,$DA,$75,$1B,$EF,$9B,$4D,$99,$8F,$49,$E8,$A9,$1D
.byte $F5,$1B,$58,$3A,$92,$25,$2D,$51,$38,$5C,$62,$05,$DD,$A9,$63,$AD
.byte $E3,$78,$2F,$37,$90,$15,$DB,$62,$58,$E2,$E8,$35,$BB,$C1,$5A,$EA
.byte $06,$FE,$28,$AA,$4F,$5D,$64,$BF,$83,$CF,$7F,$B2,$F9,$A9,$90,$BF
.byte $DD,$06,$B6,$64,$25,$8A,$E0,$24,$FA,$40,$95,$13,$91,$61,$93,$0D
.byte $69,$A8,$0E,$0B,$AE,$FD,$DF,$1A,$D4,$98,$D8,$11,$61,$E9,$16,$66
.byte $BD,$82,$1F,$2C,$E2,$74,$26,$77,$13,$E4,$6A,$25,$D7,$DE,$8A,$4F
.byte $1F,$7B,$47,$BC,$DA,$DB,$31,$E7,$2B,$06,$2C,$39,$15,$FC,$1C,$0B
.byte $1A,$3B,$A0,$0F,$55,$E5,$D8,$1C,$6D,$6C,$7F,$B8,$14,$AD,$9C,$AF
.byte $92,$B6,$60,$40,$76,$E6,$6D,$2F,$9E,$CA,$45,$6D,$54,$97,$47,$35
.byte $EE,$39,$50,$63,$47,$8C,$8A,$AB,$18,$F7,$6D,$10,$B7,$A6,$74,$0C
.byte $11,$24,$9C,$F5,$64,$5D,$FB,$16,$65,$1C,$59,$C6,$B9,$E3,$30,$52
.byte $1D,$E4,$B8,$9E,$A3,$2F,$7B,$6F,$03,$20,$24,$41,$4C,$F7,$22,$B8
.byte $92,$A7,$75,$E3,$1D,$F2,$5E,$FD,$B7,$A4,$F3,$34,$BF,$F7,$37,$CA
.byte $67,$22,$D4,$4D,$DE,$1A,$99,$58,$B2,$65,$91,$12,$F2,$8C,$65,$08
.byte $69,$E2,$9B,$D3,$94,$8C,$71,$F1,$D8,$22,$29,$53,$E8,$6A,$D9,$55
.byte $3E,$24,$42,$EF,$38,$12,$AC,$02,$35,$84,$7D,$2C,$C2,$34,$AC,$E2
.byte $4B,$AA,$E0,$31,$8F,$A0,$F2,$13,$A8,$4F,$7B,$98,$02,$16,$3B,$D4
.byte $8D,$09,$58,$A4,$FF,$46,$CA,$17,$08,$AA,$78,$02,$4A,$CF,$72,$E1
.byte $A8,$55,$52,$89,$F8,$FD,$D6,$4E,$22,$E7,$8F,$C6,$80,$F1,$BB,$3C
.byte $09,$1B,$4A,$4A,$06,$A1,$FD,$54,$E4,$BF,$D8,$27,$14,$23,$42,$90
.byte $B3,$7B,$55,$14,$77,$22,$EE,$92,$E9,$37,$76,$8C,$7D,$CF,$B7,$C7
.byte $D2,$90,$17,$48,$BB,$52,$BC,$19,$AA,$91,$9F,$DC,$0D,$AA,$C9,$24
.byte $C8,$45,$DF,$AB,$B3,$83,$A8,$9E,$0F,$AA,$62,$2F,$C4,$C0,$28,$BA
.byte $32,$56,$99,$69,$C9,$77,$4B,$62,$6B,$FF,$B6,$DD,$42,$46,$7A,$00
.byte $DA,$E9,$67,$4D,$46,$9C,$B5,$92,$04,$B5,$F6,$03,$01,$3C,$A2,$47
.byte $40,$15,$4A,$D6,$04,$39,$BC,$2F,$E9,$E1,$39,$59,$9B,$6A,$A4,$12
.byte $97,$23,$99,$30,$9E,$A6,$70,$AD,$C7,$1B,$D6,$1F,$05,$15,$D2,$5B
.byte $29,$0F,$5A,$CC,$0A,$99,$A2,$68,$5D,$58,$ED,$9C,$B9,$82,$CD,$74

View File

@ -0,0 +1,162 @@
; Tests (HL/BC/DE) instructions.
; Takes 20 seconds.
;.define PRINT_CHECKSUMS 1
.include "shell.inc"
.include "instr_test.s"
instrs:
.byte $0A,0,0 ; LD A,(BC)
.byte $1A,0,0 ; LD A,(DE)
.byte $02,0,0 ; LD (BC),A
.byte $12,0,0 ; LD (DE),A
.byte $2A,0,0 ; LD A,(HL+)
.byte $3A,0,0 ; LD A,(HL-)
.byte $22,0,0 ; LD (HL+),A
.byte $32,0,0 ; LD (HL-),A
.byte $B6,0,0 ; OR (HL)
.byte $BE,0,0 ; CP (HL)
.byte $86,0,0 ; ADD (HL)
.byte $8E,0,0 ; ADC (HL)
.byte $96,0,0 ; SUB (HL)
.byte $9E,0,0 ; SBC (HL)
.byte $A6,0,0 ; AND (HL)
.byte $AE,0,0 ; XOR (HL)
.byte $35,0,0 ; DEC (HL)
.byte $34,0,0 ; INC (HL)
.byte $CB,$06,0 ; RLC (HL)
.byte $CB,$0E,0 ; RRC (HL)
.byte $CB,$16,0 ; RL (HL)
.byte $CB,$1E,0 ; RR (HL)
.byte $CB,$26,0 ; SLA (HL)
.byte $CB,$2E,0 ; SRA (HL)
.byte $CB,$36,0 ; SWAP (HL)
.byte $CB,$3E,0 ; SRL (HL)
.byte $CB,$46,0 ; BIT 0,(HL)
.byte $CB,$4E,0 ; BIT 1,(HL)
.byte $CB,$56,0 ; BIT 2,(HL)
.byte $CB,$5E,0 ; BIT 3,(HL)
.byte $CB,$66,0 ; BIT 4,(HL)
.byte $CB,$6E,0 ; BIT 5,(HL)
.byte $CB,$76,0 ; BIT 6,(HL)
.byte $CB,$7E,0 ; BIT 7,(HL)
.byte $CB,$86,0 ; RES 0,(HL)
.byte $CB,$8E,0 ; RES 1,(HL)
.byte $CB,$96,0 ; RES 2,(HL)
.byte $CB,$9E,0 ; RES 3,(HL)
.byte $CB,$A6,0 ; RES 4,(HL)
.byte $CB,$AE,0 ; RES 5,(HL)
.byte $CB,$B6,0 ; RES 6,(HL)
.byte $CB,$BE,0 ; RES 7,(HL)
.byte $CB,$C6,0 ; SET 0,(HL)
.byte $CB,$CE,0 ; SET 1,(HL)
.byte $CB,$D6,0 ; SET 2,(HL)
.byte $CB,$DE,0 ; SET 3,(HL)
.byte $CB,$E6,0 ; SET 4,(HL)
.byte $CB,$EE,0 ; SET 5,(HL)
.byte $CB,$F6,0 ; SET 6,(HL)
.byte $CB,$FE,0 ; SET 7,(HL)
.byte $27,0,0 ; DAA
instrs_end:
test_instr:
ld c,$00
call test
ld c,$10
call test
ld c,$E0
call test
ld c,$F0
call test
ret
test:
; Go through each value for A
ld hl,values
a_loop:
ld b,(hl)
push hl
; Go through each value for (HL)
ld hl,values
values_loop:
push bc
push hl
push bc
; BC
ld a,(hl+)
ld bc,rp_temp
ld (rp_temp),a
; DE
ld a,(hl+)
ld de,rp_temp+1
ld (rp_temp+1),a
; HL
ld a,(hl)
ld hl,rp_temp+2
ld (rp_temp+2),a
; AF
pop af
; call print_regs
jp instr
instr_done:
; Checksum AF, HL, and (HL)
push hl
push af
call update_crc_fast
pop hl
ld a,l
call update_crc_fast
pop bc
ld a,b
call update_crc_fast
ld a,c
call update_crc_fast
ld a,(rp_temp)
call update_crc_fast
ld a,(rp_temp+1)
call update_crc_fast
ld a,(rp_temp+2)
call update_crc_fast
pop hl
pop bc
inc hl
ld a,l
cp <values_end
jr nz,values_loop
pop hl
inc hl
ld a,l
cp <values_end
jr nz,a_loop
ret
values:
.byte $00,$01,$0F,$10,$1F,$7F,$80,$F0,$FF,$02,$04,$08,$20,$40
values_end:
.byte $00,$01,$0F,$10,$1F,$7F,$80,$F0,$FF,$02,$04,$08,$20,$40
checksums:
.byte $E0,$E5,$09,$A7,$FB,$28,$0D,$AE,$AC,$BB,$91,$D8,$B3,$E2,$AF,$C4
.byte $3D,$B5,$02,$07,$4F,$6E,$5B,$7E,$AE,$02,$E7,$14,$DC,$D9,$BE,$6D
.byte $F1,$48,$A9,$42,$67,$08,$FE,$57,$06,$6A,$A9,$B1,$FD,$A5,$84,$F0
.byte $82,$FC,$24,$A9,$A8,$1D,$BB,$E2,$F8,$23,$8C,$DE,$0E,$1D,$64,$D1
.byte $05,$E0,$24,$41,$53,$75,$47,$55,$F4,$D9,$10,$6A,$38,$16,$28,$D8
.byte $D1,$28,$A3,$E0,$A2,$05,$B8,$FE,$B0,$F4,$F5,$8F,$4B,$39,$03,$B0
.byte $8A,$07,$BA,$90,$25,$99,$A7,$78,$E6,$9A,$D1,$49,$C9,$B2,$A3,$E5
.byte $36,$34,$CB,$5A,$97,$42,$71,$09,$39,$87,$25,$EC,$54,$EE,$C5,$B3
.byte $FC,$B5,$6F,$BD,$0B,$D8,$46,$6F,$6A,$27,$81,$9F,$F8,$38,$E2,$71
.byte $55,$19,$21,$83,$4B,$85,$9F,$4B,$A1,$78,$14,$60,$58,$08,$D9,$57
.byte $11,$8C,$83,$9A,$9F,$01,$D1,$90,$E8,$82,$0B,$5A,$BD,$75,$86,$21
.byte $DF,$83,$E9,$23,$1E,$B6,$7F,$D1,$4A,$18,$A5,$8E,$CF,$CF,$CA,$51
.byte $3F,$03,$A4,$96,$C3,$1F,$9E,$88,$0C,$DF,$1F,$B1

View File

@ -0,0 +1,215 @@
; Sound chip utilities
; Turns APU off
; Preserved: BC, DE, HL
sound_off:
wreg NR52,0
ret
; Turns APU on
; Preserved: BC, DE, HL
sound_on:
wreg NR52,$80 ; power
wreg NR51,$FF ; mono
wreg NR50,$77 ; volume
ret
; Synchronizes to APU length counter within
; tens of clocks. Uses square 2 channel.
; Preserved: BC, DE, HL
sync_apu:
wreg NR24,$00 ; disable length
wreg NR21,$3E ; length = 2 (in case of extra len clk)
wreg NR22,$08 ; silent without disabling channel
wreg NR24,$C0 ; start length
- lda NR52 ; wait for length to reach zero
and $02
jr nz,-
ret
; Synchronizes to first square sweep within
; tens of clocks. Uses square 1 channel.
; Preserved: BC, DE, HL
sync_sweep:
wreg NR10,$11 ; sweep period = 1, shift = 1
wreg NR12,$08 ; silent without disabling channel
wreg NR13,$FF ; freq = $3FF
wreg NR14,$83 ; start
- lda NR52
and $01
jr nz,-
ret
; Copies 16-byte wave from (HL) to wave RAM
; Preserved: BC, DE
load_wave:
push bc
wreg NR30,$00 ; disable while writing
ld c,$30
- ld a,(hl+)
ld ($FF00+c),a
inc c
bit 6,c
jr z,-
pop bc
ret
; Makes short beep
; Preserved: BC, DE, HL
beep:
xor a ; sound off
sta NR52
dec a
sta NR52 ; sound on
sta NR51 ; mono
sta NR50 ; volume
wreg NR12,$F1 ; volume, envelope rate
wreg NR14,$86 ; note on, pitch
delay_msec 250
ret
; Marks sound with bits of A encoded into volume
; Preserved: BC, DE, HL
mark_sound:
push bc
ld c,a
ld b,8
wreg NR10,0
wreg NR11,$80
wreg NR13,$F8
- ld a,$60
rl c
jr nc,+
ld a,$A0
+ sta NR12
wreg NR14,$87
delay_usec 300
wreg NR12,0
delay_usec 100
dec b
jr nz,-
pop bc
ret
; Fills wave RAM with A
; Preserved: BC, DE, HL
fill_wave:
push bc
ld c,$30
- ld ($FF00+c),a
inc c
bit 6,c
jr z,-
pop bc
ret
; Gets current length counter value for
; channel with mask A into A. Length counter
; must be enabled for that channel.
; Preserved: BC, DE, HL
get_len_a:
push bc
ld c,a
ld b,0
- lda NR52 ; 3
and c ; 1
jr z,+ ; 2
delay 4096-10
inc b ; 1
jr nz,- ; 3
+ ld a,b
pop bc
ret
; Synchronizes exactly to length clock. Next length clock
; occurs by 4079 clocks after this returns. Uses NR2x.
; Preserved: AF, BC, DE, HL
sync_length:
push af
push hl
ld hl,NR52
wreg NR22,$08 ; silent without disabling channel
wreg NR24,$40 ; avoids extra length clock on trigger
wreg NR21,-2 ; length = 2, in case clock occurs immediately
wreg NR24,$C0 ; start length
; Coarse sync
ld a,$02
- and (hl)
jr nz,-
; Fine sync. Slowly moves "forward" until
; length clock occurs just before reading NR52.
- delay 4097-20
wreg NR21,-1 ; 5
wreg NR24,$C0 ; 5
lda NR52 ; 3
delay 2 ; 2
and $02 ; 2
jr nz,- ; 3
pop hl
pop af
ret
; Delays n*4096 cycles
; Preserved: BC, DE, HL
.macro delay_frames ; n
ld a,\1
call delay_frames_
.endm
; Delays A*4096+13 cycles (including CALL)
; Preserved: BC, DE, HL
delay_a_frames:
or a ; 1
jr nz,+ ; 3
; -1
ret
delay_frames_: ; delays 4096*A-2 cycles (including CALL)
push af ; 4
ld a,256-13-20-12 ; 2
jr ++ ; 3
+
- push af ; 4
ld a,256-13-20 ; 2
++ call delay_a_20_cycles
delay 4096-256
pop af ; 3
dec a ; 1
jr nz,- ; 3
; -1
ret
.macro test_chan_timing ; chan, iter
ld a,\1
call print_dec
call print_space
ld a,\2
- push af
test_chan 1<<\1, \1*5+NR10
pop af
dec a
jr nz,-
call print_newline
.endm
.macro test_chans ARGS iter
test_chan_timing 0,iter
test_chan_timing 1,iter
test_chan_timing 2,iter
test_chan_timing 3,iter
.endm

View File

@ -0,0 +1,121 @@
; Build as GBS music file
.memoryMap
defaultSlot 0
slot 0 $3000 size $1000
slot 1 $C000 size $1000
.endMe
.romBankSize $1000
.romBanks 2
;;;; GBS music file header
.byte "GBS"
.byte 1 ; vers
.byte 1 ; songs
.byte 1 ; first song
.word load_addr
.word reset
.word gbs_play
.word std_stack
.byte 0,0 ; timer
.ds $60,0
load_addr:
; WLA assumes we're building ROM and messes
; with bytes at the beginning, so skip them.
.ds $100,0
;;;; Shell
.include "runtime.s"
init_runtime:
ld a,$01 ; Identify as DMG hardware
ld (gb_id),a
.ifdef TEST_NAME
print_str TEST_NAME,newline,newline
.endif
ret
std_print:
sta SB
wreg SC,$81
delay 2304
ret
post_exit:
call play_byte
forever:
wreg NR52,0 ; sound off
- jp -
.ifndef CUSTOM_RESET
gbs_play:
.endif
console_flush:
console_normal:
console_inverse:
console_set_mode:
ret
; Reports A in binary as high and low tones, with
; leading low tone for reference. Omits leading
; zeroes.
; Preserved: AF, BC, DE, HL
play_byte:
push af
push hl
; HL = (A << 1) | 1
scf
rla
ld l,a
ld h,0
rl h
; Shift left until next-to-top bit is 1
- add hl,hl
bit 6,h
jr z,-
; Reset sound
delay_msec 400
wreg NR52,0 ; sound off
wreg NR52,$80 ; sound on
wreg NR51,$FF ; mono
wreg NR50,$77 ; volume
- add hl,hl
; Low or high pitch based on bit shifted out
; of HL
ld a,0
jr nc,+
ld a,$FF
+ sta NR23
; Play short tone
wreg NR21,$A0
wreg NR22,$F0
wreg NR24,$86
delay_msec 75
wreg NR22,0
wreg NR23,$F8
wreg NR24,$87
delay_msec 200
; Loop until HL = $8000
ld a,h
xor $80
or l
jr nz,-
pop hl
pop af
ret
.ends

View File

@ -0,0 +1,80 @@
; Build as GB ROM
.memoryMap
defaultSlot 0
slot 0 $0000 size $4000
slot 1 $C000 size $4000
.endMe
.romBankSize $4000 ; generates $8000 byte ROM
.romBanks 2
.cartridgeType 1 ; MBC1
.computeChecksum
.computeComplementCheck
;;;; GB ROM header
; GB header read by bootrom
.org $100
nop
jp reset
; Nintendo logo required for proper boot
.byte $CE,$ED,$66,$66,$CC,$0D,$00,$0B
.byte $03,$73,$00,$83,$00,$0C,$00,$0D
.byte $00,$08,$11,$1F,$88,$89,$00,$0E
.byte $DC,$CC,$6E,$E6,$DD,$DD,$D9,$99
.byte $BB,$BB,$67,$63,$6E,$0E,$EC,$CC
.byte $DD,$DC,$99,$9F,$BB,$B9,$33,$3E
; Internal name
.ifdef ROM_NAME
.byte ROM_NAME
.endif
; CGB/DMG requirements
.org $143
.ifdef REQUIRE_CGB
.byte $C0
.else
.ifndef REQUIRE_DMG
.byte $80
.endif
.endif
.org $200
;;;; Shell
.include "runtime.s"
.include "console.s"
init_runtime:
call console_init
.ifdef TEST_NAME
print_str TEST_NAME,newline,newline
.endif
ret
std_print:
push af
sta SB
wreg SC,$81
delay 2304
pop af
jp console_print
post_exit:
call console_show
call play_byte
forever:
wreg NR52,0 ; sound off
- jr -
play_byte:
ret
.ends

View File

@ -0,0 +1,98 @@
; Multiple checksum table handling
.define next_checksum bss+0
.redefine bss bss+2
; If PRINT_CHECKSUMS is defined, checksums are printed
; rather than compared.
; Initializes multiple checksum handler to use checksums
; table (defined by user).
; Preserved: BC, DE, HL
checksums_init:
ld a,<checksums
ld (next_checksum),a
ld a,>checksums
ld (next_checksum+1),a
ret
; Compares current checksum with next checksum in
; list. Z if they match, NZ if not.
; Preserved: BC, DE, HL
checksums_compare:
.ifdef PRINT_CHECKSUMS
lda checksum+3
push af
lda checksum+2
push af
lda checksum+1
push af
lda checksum+0
push af
ld a,(next_checksum)
inc a
ld (next_checksum),a
sub <checksums+1
and $03
ld a,','
jr nz,+
print_str newline,'.',"byte"
ld a,' '
+ call print_char
pop af
call @print_byte
pop af
call @print_byte
pop af
call @print_byte
ld a,'$'
call print_char
pop af
call print_hex
xor a
ret
@print_byte:
push af
ld a,'$'
call print_char
pop af
call print_hex
ld a,','
call print_char
ret
.else
push bc
push de
push hl
ld a,(next_checksum)
ld l,a
ld a,(next_checksum+1)
ld h,a
ld de,checksum
ld b,0
- ld a,(de)
xor (hl)
or b
ld b,a
inc hl
inc e
ld a,e
cp <(checksum+4)
jr nz,-
ld a,l
ld (next_checksum),a
ld a,h
ld (next_checksum+1),a
ld a,b
cp 0
pop hl
pop de
pop bc
ret
.endif

View File

@ -0,0 +1,291 @@
; Scrolling text console
; Console is 20x18 characters. Buffers lines, so
; output doesn't appear until a newline or flush.
; If scrolling isn't supported (i.e. SCY is treated
; as if always zero), the first 18 lines will
; still print properly). Also works properly if
; LY isn't supported (always reads back as the same
; value).
.define console_width 20
.define console_buf bss+0
.define console_pos bss+console_width
.define console_mode bss+console_width+1
.define console_scroll bss+console_width+2
.redefine bss bss+console_width+3
; Waits for start of LCD blanking period
; Preserved: BC, DE, HL
console_wait_vbl:
push bc
; Wait for start of vblank, with
; timeout in case LY doesn't work
; or LCD is disabled.
ld bc,-1250
- inc bc
ld a,b
or c
jr z,@timeout
lda LY
cp 144
jr nz,-
@timeout:
pop bc
ret
; Initializes text console
console_init:
call console_hide
; CGB-specific inits
ld a,(gb_id)
and gb_id_cgb
call nz,@init_cgb
; Clear nametable
ld a,' '
call @fill_nametable
; Load tiles
ld hl,TILES+$200
ld c,0
call @load_tiles
ld hl,TILES+$A00
ld c,$FF
call @load_tiles
; Init state
ld a,console_width
ld (console_pos),a
ld a,0
ld (console_mode),a
ld a,-8
ld (console_scroll),a
call console_scroll_up_
jr console_show
@fill_nametable:
ld hl,BGMAP0
ld b,4
- ld (hl),a
inc l
jr nz,-
inc h
dec b
jr nz,-
ret
@init_cgb:
; Clear palette
wreg $FF68,$80
ld b,16
- wreg $FF69,$FF
wreg $FF69,$7F
wreg $FF69,$00
wreg $FF69,$00
wreg $FF69,$00
wreg $FF69,$00
wreg $FF69,$00
wreg $FF69,$00
dec b
jr nz,-
; Clear attributes
ld a,1
ld (VBK),a
ld a,0
call @fill_nametable
ld a,0
ld (VBK),a
ret
@load_tiles:
ld de,ASCII
ld b,96
-- push bc
ld b,8
- ld a,(de)
inc de
xor c
ldi (hl),a
ldi (hl),a
dec b
jr nz,-
pop bc
dec b
jr nz,--
ret
; Shows console display
; Preserved: AF, BC, DE, HL
console_show:
push af
; Enable LCD
call console_wait_vbl
wreg LCDC,$91
wreg SCX,0
wreg BGP,$E4
jp console_apply_scroll_
; Hides console display by turning LCD off
; Preserved: AF, BC, DE, HL
console_hide:
push af
; LCD off
call console_wait_vbl
wreg LCDC,$11
pop af
ret
; Changes to normal text mode
; Preserved: BC, DE, HL
console_normal:
xor a
jr console_set_mode
; Changes to inverse text mode
; Preserved: BC, DE, HL
console_inverse:
ld a,$80
; Changes console mode to A.
; 0: Normal, $80: Inverse
; Preserved: BC, DE, HL
console_set_mode:
and $80
ld (console_mode),a
ret
; Prints char A to console. Will not appear until
; a newline or flush occurs.
; Preserved: AF, BC, DE, HL
console_print:
push af
cp 10
jr z,console_newline_
push hl
push af
ld hl,console_pos
ldi a,(hl)
cp <console_buf
jr nz,@not_at_end
; Newline if at end of current line. If this
; were done after writing to buffer, calling
; console_newline would print extra newline.
; Doing it before eliminates this.
; Ignore any spaces at end of line
pop af
cp ' '
jr z,@ignore_space
call console_newline
push af
@not_at_end:
pop af
or (hl) ; apply current attributes
dec l ; hl = console_pos
dec (hl) ; console_pos = console_pos - 1
ld l,(hl) ; hl = position in buffer
ld (hl),a
@ignore_space
pop hl
pop af
ret
; Displays current line and starts new one
; Preserved: AF, BC, DE, HL
console_newline:
push af
console_newline_:
call console_wait_vbl
call console_flush_
call console_scroll_up_
call console_flush_
jp console_apply_scroll_
console_scroll_up_:
push bc
push hl
; Scroll up 8 pixels
ld a,(console_scroll)
add 8
ld (console_scroll),a
; Start new clear line
ld a,' '
ld hl,console_buf + console_width - 1
ld b,console_width
- ldd (hl),a
dec b
jr nz,-
ld a,<(console_buf + console_width)
ld (console_pos),a
pop hl
pop bc
ret
; Displays current line's contents without scrolling.
; Preserved: A, BC, DE, HL
console_flush:
push af
call console_wait_vbl
call console_flush_
console_apply_scroll_:
ld a,(console_scroll)
sub 136
sta SCY
pop af
ret
console_flush_:
push de
push hl
; Address of row in nametable
ld a,(console_scroll)
ld l,a
ld h,(>BGMAP0) >> 2
add hl,hl
add hl,hl
; Copy line
ld de,console_buf + console_width
- dec e
ld a,(de)
ldi (hl),a
ld a,e
cp <console_buf
jr nz,-
pop hl
pop de
ret
ASCII:
.incbin "console.bin"

View File

@ -0,0 +1,64 @@
; CPU speed manipulation.
; Switches to normal speed. No effect on DMG.
; Preserved: BC, DE, HL
cpu_norm:
; Do nothing if not CGB
ld a,(gb_id)
and gb_id_cgb
ret z
lda KEY1
rlca
ret nc
jr cpu_speed_toggle
; Switches to double speed. No effect on DMG.
; Preserved: BC, DE, HL
cpu_fast:
; Do nothing if not CGB
ld a,(gb_id)
and gb_id_cgb
ret z
lda KEY1
rlca
ret c
cpu_speed_toggle:
di
lda IE
push af
xor a
sta IE
sta IF
wreg P1,$30
wreg KEY1,1
stop
nop
pop af
sta IE
ret
; Determines current CPU speed without using KEY1.
; A=1 if fast, 0 if normal. Always 0 on DMG.
; Preserved: BC, DE,HL
get_cpu_speed:
push bc
call sync_apu
wreg NR14,$C0
wreg NR11,-1
wreg NR12,8
wreg NR14,$C0
ld bc,-$262
- inc bc
lda NR52
and 1
jr nz,-
ld a,0
bit 7,b
jr nz,+
inc a
+ pop bc
ret

View File

@ -0,0 +1,78 @@
; CRC-32 checksum calculation
.define checksum dp+0 ; little-endian, complemented
.redefine dp dp+4
; Initializes checksum module. Might initialize tables
; in the future.
init_crc:
jr reset_crc
; Clears CRC
; Preserved: BC, DE, HL
reset_crc:
ld a,$FF
sta checksum+0
sta checksum+1
sta checksum+2
sta checksum+3
ret
; Updates current checksum with byte A
; Preserved: AF, BC, DE, HL
; Time: 237 cycles average
update_crc:
; 65 cycles + 8*cycles per bit
; min cycles per bit: 14
; max cycles per bit: 29
push af
push bc
push de
push hl
ld hl,checksum+3
ld b,(hl)
dec l
ld c,(hl)
dec l
ld d,(hl)
dec l
xor (hl)
ld h,8
- srl b
rr c
rr d
rra
jr nc,+
ld e,a
ld a,b
xor $ED
ld b,a
ld a,c
xor $B8
ld c,a
ld a,d
xor $83
ld d,a
ld a,e
xor $20
+ dec h
jr nz,-
ld h,>checksum
ldi (hl),a
ld (hl),d
inc l
ld (hl),c
inc l
ld (hl),b
pop hl
pop de
pop bc
pop af
ret

View File

@ -0,0 +1,88 @@
; Fast table-based CRC-32
.define crc_tables (bss+$FF)&$FF00 ; 256-byte aligned
.redefine bss crc_tables+$400
; Initializes fast CRC tables and resets checksum.
; Time: 47 msec
init_crc_fast:
ld l,0
@next:
xor a
ld c,a
ld d,a
ld e,l
ld h,8
- rra
rr c
rr d
rr e
jr nc,+
xor $ED
ld b,a
ld a,c
xor $B8
ld c,a
ld a,d
xor $83
ld d,a
ld a,e
xor $20
ld e,a
ld a,b
+ dec h
jr nz,-
ld h,>crc_tables
ld (hl),e
inc h
ld (hl),d
inc h
ld (hl),c
inc h
ld (hl),a
inc l
jr nz,@next
jp init_crc
; Faster version of update_crc
; Preserved: BC, DE
; Time: 50 cycles (including CALL)
update_crc_fast:
; Fastest inline macro version of update_crc_fast
; Time: 40 cycles
; Size: 28 bytes
.macro update_crc_fast
ld l,a ; 1
lda checksum ; 3
xor l ; 1
ld l,a ; 1
ld h,>crc_tables ; 2
lda checksum+1 ; 3
xor (hl) ; 2
inc h ; 1
sta checksum ; 3
lda checksum+2 ; 3
xor (hl) ; 2
inc h ; 1
sta checksum+1 ; 3
lda checksum+3 ; 3
xor (hl) ; 2
inc h ; 1
sta checksum+2 ; 3
ld a,(hl) ; 2
sta checksum+3 ; 3
.endm
update_crc_fast
ret

View File

@ -0,0 +1,220 @@
; Delays in cycles, milliseconds, etc.
; All routines are re-entrant (no global data). Routines never
; touch BC, DE, or HL registers. These ASSUME CPU is at normal
; speed. If running at double speed, msec/usec delays are half advertised.
; Delays n cycles, from 0 to 16777215
; Preserved: AF, BC, DE, HL
.macro delay ARGS n
.if n < 0
.printt "Delay must be >= 0"
.fail
.endif
.if n > 16777215
.printt "Delay must be < 16777216"
.fail
.endif
delay_ n&$FFFF, n>>16
.endm
; Delays n clocks, from 0 to 16777216*4. Must be multiple of 4.
; Preserved: AF, BC, DE, HL
.macro delay_clocks ARGS n
.if n # 4 != 0
.printt "Delay must be a multiple of 4"
.fail
.endif
delay_ (n/4)&$FFFF,(n/4)>>16
.endm
; Delays n microseconds (1/1000000 second)
; n can range from 0 to 4000 usec.
; Preserved: AF, BC, DE, HL
.macro delay_usec ARGS n
.if n < 0
.printt "Delay must be >= 0"
.fail
.endif
.if n > 4000
.printt "Delay must be <= 4000 usec"
.fail
.endif
delay_ ((n * 1048576 + 500000) / 1000000)&$FFFF,((n * 1048576 + 500000) / 1000000)>>16
.endm
; Delays n milliseconds (1/1000 second)
; n can range from 0 to 10000 msec.
; Preserved: AF, BC, DE, HL
.macro delay_msec ARGS n
.if n < 0
.printt "Delay must be >= 0"
.fail
.endif
.if n > 10000
.printt "Delay must be <= 10000 msec"
.fail
.endif
delay_ ((n * 1048576 + 500) / 1000)&$FFFF, ((n * 1048576 + 500) / 1000)>>16
.endm
; All the low/high quantities are to deal wla-dx's asinine
; restriction full expressions must evaluate to a 16-bit
; value. If the author ever rectifies this, all "high"
; arguments can be treated as zero and removed. Better yet,
; I'll just find an assembler that didn't crawl out of
; the sewer (this is one of too many bugs I've wasted
; hours working around).
.define max_short_delay 28
.macro delay_long_ ARGS n, high
; 0+ to avoid assembler treating as memory read
ld a,0+(((high<<16)+n) - 11) >> 16
call delay_65536a_9_cycles_
delay_nosave_ (((high<<16)+n) - 11)&$FFFF, 0
.endm
; Doesn't save AF, allowing minimization of AF save/restore
.macro delay_nosave_ ARGS n, high
; 65536+11 = maximum delay using delay_256a_9_cycles_
; 255+22 = maximum delay using delay_a_20_cycles
; 22 = minimum delay using delay_a_20_cycles
.if high > 1
delay_long_ n, high
.else
.if high*n > 11
delay_long_ n, high
.else
.if (high*(255+22+1))|n > 255+22
ld a,>(((high<<16)+n) - 11)
call delay_256a_9_cycles_
delay_nosave_ <(((high<<16)+n) - 11), 0
.else
.if n >= 22
ld a,n - 22
call delay_a_20_cycles
.else
delay_short_ n
.endif
.endif
.endif
.endif
.endm
.macro delay_ ARGS low, high
.if (high*(max_short_delay+1))|low > max_short_delay
push af
delay_nosave_ ((high<<16)+low - 7)&$FFFF, ((high<<16)+low - 7)>>16
pop af
.else
delay_short_ low
.endif
.endm
; Delays A cycles + overhead
; Preserved: BC, DE, HL
; Time: A+20 cycles (including CALL)
delay_a_20_cycles:
- sub 5 ; 2
jr nc,- ;3/2 do multiples of 5
rra ; 1
jr nc,+ ;3/2 bit 0
+ adc 1 ; 2
ret nc ;5/2 -1: 0 cycles
ret z ;5/2 0: 2 cycles
nop ; 1 1: 4 cycles
ret ; 4 (thanks to dclxvi for original algorithm)
; Delays A*256 cycles + overhead
; Preserved: BC, DE, HL
; Time: A*256+12 cycles (including CALL)
delay_256a_12_cycles:
or a ; 1
ret z ; 5/2
delay_256a_9_cycles_:
- delay 256-4
dec a ; 1
jr nz,- ;3/2
ret ; 4
; Delays A*65536 cycles + overhead
; Preserved: BC, DE, HL
; Time: A*65536+12 cycles (including CALL)
delay_65536a_12_cycles:
or a ; 1
ret z ;5/2
delay_65536a_9_cycles_:
- delay 65536-4
dec a ; 1
jr nz,- ;3/2
ret ; 4
; Delays H*256+L cycles + overhead
; Preserved: AF, BC, DE, HL
; Time: H*256+L+51 cycles
delay_hl_51_cycles:
push af
ld a,h
call delay_256a_12_cycles
ld a,l
call delay_a_20_cycles
pop af
ret
; delay_short_ macro calls into these
.ds max_short_delay-10,$00 ; NOP repeated several times
delay_unrolled_:
ret
.macro delay_short_ ARGS n
.if n < 0
.fail
.endif
.if n > max_short_delay
.fail
.endif
.if n == 1
nop
.endif
.if n == 2
nop
nop
.endif
.if n == 3
.byte $18,$00 ; JR +0
.endif
.if n == 4
.byte $18,$00 ; JR +0
nop
.endif
.if n == 5
.byte $18,$00 ; JR +0
nop
nop
.endif
.if n == 6
.byte $18,$00 ; JR +0
.byte $18,$00 ; JR +0
.endif
.if n == 7
push af
pop af
.endif
.if n == 8
push af
pop af
nop
.endif
.if n == 9
push af
pop af
nop
nop
.endif
.if n >= 10
call delay_unrolled_ + 10 - n
.endif
.endm

View File

@ -0,0 +1,64 @@
; Game Boy hardware addresses
; Memory
.define VRAM $8000 ; video memory
.define TILES $8000 ; tile images
.define BGMAP0 $9800 ; first 32x32 tilemap
.define BGMAP1 $9C00 ; second 32x32 tilemap
.define WRAM $C000 ; internal memory
.define OAM $FE00 ; sprite memory
.define HRAM $FF80 ; fast memory for LDH
.define P1 $FF00
; Game link I/O
.define SB $FF01
.define SC $FF02
; Interrupts
.define DIV $FF04
.define TIMA $FF05
.define TMA $FF06
.define TAC $FF07
.define IF $FF0F
.define IE $FFFF
; LCD registers
.define LCDC $FF40 ; control
.define STAT $FF41 ; status
.define SCY $FF42 ; scroll Y
.define SCX $FF43 ; scroll X
.define LY $FF44 ; current Y being rendered
.define BGP $FF47
.define KEY1 $FF4D ; for changing CPU speed
.define VBK $FF4F
; Sound registers
.define NR10 $FF10
.define NR11 $FF11
.define NR12 $FF12
.define NR13 $FF13
.define NR14 $FF14
.define NR21 $FF16
.define NR22 $FF17
.define NR23 $FF18
.define NR24 $FF19
.define NR30 $FF1A
.define NR31 $FF1B
.define NR32 $FF1C
.define NR33 $FF1D
.define NR34 $FF1E
.define NR41 $FF20
.define NR42 $FF21
.define NR43 $FF22
.define NR44 $FF23
.define NR50 $FF24
.define NR51 $FF25
.define NR52 $FF26
.define WAVE $FF30

View File

@ -0,0 +1,105 @@
; Framework for CPU instruction tests
; Calls test_instr with each instruction copied
; to instr, with a JP instr_done after it.
; Verifies checksum after testing instruction and
; prints opcode if it's wrong.
.include "checksums.s"
.include "cpu_speed.s"
.include "apu.s"
.include "crc_fast.s"
.define instr $DEF8
.define rp_temp (instr-4)
.define temp bss
; Sets SP to word at addr
; Preserved: BC, DE
.macro ldsp ; addr
ld a,(\1)
ld l,a
ld a,((\1)+1)
ld h,a
ld sp,hl
.endm
main:
call cpu_fast
call init_crc_fast
call checksums_init
set_test 0
ld hl,instrs
- ; Copy instruction
ld a,(hl+)
ld (instr),a
ld a,(hl+)
ld (instr+1),a
ld a,(hl+)
ld (instr+2),a
push hl
; Put JP instr_done after it
ld a,$C3
ld (instr+3),a
ld a,<instr_done
ld (instr+4),a
ld a,>instr_done
ld (instr+5),a
call reset_crc
call test_instr
call checksums_compare
jr z,passed
set_test 1
ld a,(instr)
call print_a
cp $CB
jr nz,+
ld a,(instr+1)
call print_a
+
passed:
; Next instruction
pop hl
ld a,l
cp <instrs_end
jr nz,-
ld a,h
cp >instrs_end
jr nz,-
jp tests_done
; Updates checksum with AF, BC, DE, and HL
checksum_af_bc_de_hl:
push hl
push af
update_crc_fast
pop hl
ld a,l
update_crc_fast
ld a,b
update_crc_fast
ld a,c
update_crc_fast
ld a,d
update_crc_fast
ld a,e
update_crc_fast
pop de
ld a,d
update_crc_fast
ld a,e
update_crc_fast
ret

View File

@ -0,0 +1,73 @@
; General macros
; Reads A from addr, from $FF00 to $FFFF
; Preserved: F, BC, DE, HL
; Time: 3 cycles
.macro lda ARGS addr
ldh a,(addr - $FF00)
.endm
; Writes A to addr, from $FF00 to $FFFF
; Preserved: AF, BC, DE, HL
; Time: 3 cycles
.macro sta ARGS addr
ldh (addr - $FF00),a
.endm
; Writes immediate data to addr, from $FF00 to $FFFF
; Preserved: F, BC, DE, HL
; Time: 5 cycles
.macro wreg ARGS addr, data
ld a,data
sta addr
.endm
; Calls routine multiple times, with A having the
; value 'start' the first time, 'start+step' the
; second time, up to 'end' for the last time.
; Preserved: BC, DE, HL
.macro for_loop ; routine,start,end,step
ld a,\2
for_loop\@:
push af
call \1
pop af
add \4
cp <(\3 + \4)
jr nz,for_loop\@
.endm
; Calls routine n times. The value of A in the routine
; counts from 0 to n-1.
; Preserved: BC, DE, HL
.macro loop_n_times ; routine,n
for_loop \1,0,\2 - 1,+1
.endm
; Same as for_loop, but counts with 16-bit value in BC.
; Preserved: DE, HL
.macro for_loop16 ; routine,start,end,step
ld bc,\2
for_loop16\@:
push bc
call \1
pop bc
ld a,c
add <\4
ld c,a
ld a,b
adc >\4
ld b,a
cp >(\3+\4)
jr nz,for_loop16\@
ld a,c
cp <(\3+\4)
jr nz,for_loop16\@
.endm

View File

@ -0,0 +1,38 @@
; RST handlers
.bank 0 slot 0
.org 0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret
.ds 6,0
inc a
ret

View File

@ -0,0 +1,177 @@
; Printing of numeric values
; Prints value of indicated register/pair
; as 2/4 hex digits, followed by a space.
; Updates checksum with printed values.
; Preserved: AF, BC, DE, HL
print_regs:
call print_af
call print_bc
call print_de
call print_hl
call print_newline
ret
print_a:
push af
print_a_:
call print_hex
ld a,' '
call print_char_nocrc
pop af
ret
print_af:
push af
call print_hex
pop af
print_f:
push bc
push af
pop bc
call print_c
pop bc
ret
print_b:
push af
ld a,b
jr print_a_
print_c:
push af
ld a,c
jr print_a_
print_d:
push af
ld a,d
jr print_a_
print_e:
push af
ld a,e
jr print_a_
print_h:
push af
ld a,h
jr print_a_
print_l:
push af
ld a,l
jr print_a_
print_bc:
push af
push bc
print_bc_:
ld a,b
call print_hex
ld a,c
pop bc
jr print_a_
print_de:
push af
push bc
ld b,d
ld c,e
jr print_bc_
print_hl:
push af
push bc
ld b,h
ld c,l
jr print_bc_
; Prints A as two hex chars and updates checksum
; Preserved: BC, DE, HL
print_hex:
call update_crc
print_hex_nocrc:
push af
swap a
call +
pop af
+ and $0F
cp 10
jr c,+
add 7
+ add '0'
jp print_char_nocrc
; Prints char_nz if Z flag is clear,
; char_z if Z flag is set.
; Preserved: AF, BC, DE, HL
.macro print_nz ARGS char_nz, char_z
push af
ld a,char_nz
jr nz,print_nz\@
ld a,char_z
print_nz\@:
call print_char
pop af
.endm
; Prints char_nc if C flag is clear,
; char_c if C flag is set.
; Preserved: AF, BC, DE, HL
.macro print_nc ARGS char_nc, char_c
push af
ld a,char_nc
jr nz,print_nc\@
ld a,char_c
print_nc\@:
call print_char
pop af
.endm
; Prints A as 2 decimal digits
; Preserved: AF, BC, DE, HL
print_dec2:
push af
push bc
jr +
; Prints A as 1-3 digit decimal value
; Preserved: AF, BC, DE, HL
print_dec:
push af
push bc
cp 10
jr c,++
ld c,100
cp c
call nc,@digit
+ ld c,10
call @digit
++ add '0'
call print_char
pop bc
pop af
ret
@digit:
ld b,'0'-1
- inc b
sub c
jr nc,-
add c
ld c,a
ld a,b
call print_char
ld a,c
ret

View File

@ -0,0 +1,98 @@
; Main printing routine that checksums and
; prints to output device
; Character that does equivalent of print_newline
.define newline 10
; Prints char without updating checksum
; Preserved: BC, DE, HL
.define print_char_nocrc bss
.redefine bss bss+3
; Initializes printing. HL = print routine
init_printing:
ld a,l
ld (print_char_nocrc+1),a
ld a,h
ld (print_char_nocrc+2),a
jr show_printing
; Hides/shows further printing
; Preserved: BC, DE, HL
hide_printing:
ld a,$C9 ; RET
jr +
show_printing:
ld a,$C3 ; JP (nn)
+ ld (print_char_nocrc),a
ret
; Prints character and updates checksum UNLESS
; it's a newline.
; Preserved: AF, BC, DE, HL
print_char:
push af
cp newline
call nz,update_crc
call print_char_nocrc
pop af
ret
; Prints space. Does NOT update checksum.
; Preserved: AF, BC, DE, HL
print_space:
push af
ld a,' '
call print_char_nocrc
pop af
ret
; Advances to next line. Does NOT update checksum.
; Preserved: AF, BC, DE, HL
print_newline:
push af
ld a,newline
call print_char_nocrc
pop af
ret
; Prints immediate string
; Preserved: AF, BC, DE, HL
.macro print_str ; string,string2
push hl
call print_str_
.byte \1
.if NARGS > 1
.byte \2
.endif
.if NARGS > 2
.byte \3
.endif
.byte 0
pop hl
.endm
print_str_:
pop hl
call print_str_hl
jp hl
; Prints zero-terminated string pointed to by HL.
; On return, HL points to byte AFTER zero terminator.
; Preserved: AF, BC, DE
print_str_hl:
push af
jr +
- call print_char
+ ldi a,(hl)
or a
jr nz,-
pop af
ret

View File

@ -0,0 +1,142 @@
; Common routines and runtime
; Must be defined by target-specific runtime:
;
; init_runtime: ; target-specific inits
; std_print: ; default routine to print char A
; post_exit: ; called at end of std_exit
; report_byte: ; report A to user
.define RUNTIME_INCLUDED 1
.ifndef bss
; address of next normal variable
.define bss $D800
.endif
.ifndef dp
; address of next direct-page ($FFxx) variable
.define dp $FF80
.endif
; DMG/CGB hardware identifier
.define gb_id_cgb $10 ; mask for testing CGB bit
.define gb_id_devcart $04 ; mask for testing "on devcart" bit
.define gb_id bss
.redefine bss bss+1
; Stack is normally here
.define std_stack $DFFF
; Copies $1000 bytes from HL to $C000, then jumps to it.
; A is preserved for jumped-to code.
copy_to_wram_then_run:
ld b,a
ld de,$C000
ld c,$10
- ldi a,(hl)
ld (de),a
inc e
jr nz,-
inc d
dec c
jr nz,-
ld a,b
jp $C000
.ifndef CUSTOM_RESET
reset:
; Run code from $C000, as is done on devcart. This
; ensures minimal difference in how it behaves.
ld hl,$4000
jp copy_to_wram_then_run
.bank 1 slot 1
.org $0 ; otherwise wla pads with lots of zeroes
jp std_reset
.endif
; Common routines
.include "gb.inc"
.include "macros.inc"
.include "delay.s"
.include "crc.s"
.include "printing.s"
.include "numbers.s"
.include "testing.s"
; Sets up hardware and runs main
std_reset:
; Init hardware
di
ld sp,std_stack
; Save DMG/CGB id
ld (gb_id),a
; Init hardware
.ifndef BUILD_GBS
wreg TAC,$00
wreg IF,$00
wreg IE,$00
.endif
wreg NR52,0 ; sound off
wreg NR52,$80 ; sound on
wreg NR51,$FF ; mono
wreg NR50,$77 ; volume
; TODO: clear all memory?
ld hl,std_print
call init_printing
call init_testing
call init_runtime
call reset_crc ; in case init_runtime prints anything
delay_msec 250
; Run user code
call main
; Default is to successful exit
ld a,0
jp exit
; Exits code and reports value of A
exit:
ld sp,std_stack
push af
call +
pop af
jp post_exit
+ push af
call print_newline
call show_printing
pop af
; Report exit status
cp 1
; 0: ""
ret c
; 1: "Failed"
jr nz,+
print_str "Failed",newline
ret
; n: "Failed #n"
+ print_str "Failed #"
call print_dec
call print_newline
ret
; returnOrg puts this code AFTER user code.
.section "runtime" returnOrg

View File

@ -0,0 +1,176 @@
; Diagnostic and testing utilities
.define result bss+0
.define test_name bss+1
.redefine bss bss+3
; Sets test code and optional error text
; Preserved: AF, BC, DE, HL
.macro set_test ; code[,text[,text2]]
push hl
call set_test_
jr @set_test\@
.byte \1
.if NARGS > 1
.byte \2
.endif
.if NARGS > 2
.byte \3
.endif
.byte 0
@set_test\@:
pop hl
.endm
set_test_:
pop hl
push hl
push af
inc hl
inc hl
ldi a,(hl)
ld (result),a
ld a,l
ld (test_name),a
ld a,h
ld (test_name+1),a
pop af
ret
; Initializes testing module
init_testing:
set_test $FF
call init_crc
ret
; Reports "Passed", then exits with code 0
tests_passed:
call print_newline
print_str "Passed"
ld a,0
jp exit
; Reports "Done" if set_test has never been used,
; "Passed" if set_test 0 was last used, or
; failure if set_test n was last used.
tests_done:
ld a,(result)
inc a
jr z,+
dec a
jr z,tests_passed
jr test_failed
+ print_str "Done"
ld a,0
jp exit
; Reports current error text and exits with result code
test_failed:
ld a,(test_name)
ld l,a
ld a,(test_name+1)
ld h,a
ld a,(hl)
or a
jr z,+
call print_newline
call print_str_hl
call print_newline
+
ld a,(result)
cp 1 ; if a = 0 then a = 1
adc 0
jp exit
; Prints checksum as 8-character hex value
; Preserved: AF, BC, DE, HL
print_crc:
push af
; Must read checksum entirely before printing,
; since printing updates it.
lda checksum
cpl
push af
lda checksum+1
cpl
push af
lda checksum+2
cpl
push af
lda checksum+3
cpl
call print_hex
pop af
call print_hex
pop af
call print_hex
pop af
call print_a
pop af
ret
; If checksum doesn't match expected, reports failed test.
; Passing 0 just prints checksum. Clears checksum afterwards.
.macro check_crc ARGS crc
.if crc == 0
call show_printing
call print_newline
call print_crc
.else
ld bc,(crc >> 16) ~ $FFFF
ld de,(crc & $FFFF) ~ $FFFF
call check_crc_
.endif
.endm
check_crc_:
lda checksum+0
cp e
jr nz,+
lda checksum+1
cp d
jr nz,+
lda checksum+2
cp c
jr nz,+
lda checksum+3
cp b
jr nz,+
jp reset_crc
+ call print_crc
jp test_failed
; Updates checksum with bytes from addr to addr+size-1
.macro checksum_mem ARGS addr,size
ld hl,addr
ld bc,size
call checksum_mem_
.endm
checksum_mem_:
- ldi a,(hl)
call update_crc
dec bc
ld a,b
or c
jr nz,-
ret

View File

@ -0,0 +1,2 @@
[objects]
test.o

View File

@ -0,0 +1,21 @@
.incdir "common"
; GBS music file
.ifdef BUILD_GBS
.include "build_gbs.s"
.endif
; Devcart
.ifdef BUILD_DEVCART
.include "build_devcart.s"
.endif
; Sub-test in a multi-test ROM
.ifdef BUILD_MULTI
.include "build_multi.s"
.endif
; GB ROM (default)
.ifndef RUNTIME_INCLUDED
.include "build_rom.s"
.endif

View File

@ -0,0 +1,86 @@
Game Boy Sound Hardware Tests
-----------------------------
These tests verify aspects of the sound hardware that the CPU can
observe. The ROMs and GBSs are either for DMG or CGB hardware, as there
are several differences.
Multi-ROM
---------
In the main directory is a single ROM/GBS which runs all the tests. It
prints a test's number, runs the test, then "ok" if it passes, otherwise
a failure code. Once all tests have completed it either reports that all
tests passed, or reports the number of the first failed test as the
result code (1 = first). Finally, it makes several beeps. If a test
fails, it can be run on its own by finding the corresponding ROM/GBS in
the singles directories.
Ths compact format on screen is to avoid having the results scroll off
the top, so the test can be started and allowed to run without having to
constantly monitor the display.
Failure information
-------------------
For more information about a failure code or information printed, see
the test's source code in source/. To find failure code N, search for
"set_test N", which will usually be before the subtest which failed.
Flashes, clicks, other glitches
-------------------------------
Some tests might need to turn the screen off and on, or cause slight
audio clicks. This does not indicate failure, and should be ignored.
Only the test result reported at the end is important, unless stated
otherwise.
LCD support
-----------
Tests generally print information on screen. The tests will work fine if
run on an emulator with NO LCD support, or as an GBS which has no
inherent screen; in particular, the VBL wait routine has a timeout in
case LY doesn't reflect the current LCD line. The text printing will
also work if the LCD doesn't support scrolling.
Output to memory
----------------
Text output and the final result are also written to memory at $A000,
allowing testing a very minimal emulator that supports little more than
CPU and RAM. To reliably indicate that the data is from a test and not
random data, $A001-$A003 are written with a signature: $DE,$B0,$61. If
this is present, then the text string and final result status are valid.
$A000 holds the overall status. If the test is still running, it holds
$80, otherwise it holds the final result code.
All text output is appended to a zero-terminated string at $A004. An
emulator could regularly check this string for any additional
characters, and output them, allowing real-time text output, rather than
just printing the final output at the end.
GBS versions
------------
Many GBS-based tests require that the GBS player either not interrupt
the init routine with the play routine, or if they do, not interrupt the
play routine again if it hasn't returned yet. This is because many tests
need to run for a while without returning.
In addition to the other text output methods described above, GBS builds
report essential information bytes audibly, including the final result.
A byte is reported as a series of tones. The code is in binary, with a
low tone for 0 and a high tone for 1. The first tone is always a zero. A
final code of 0 means passed, 1 means failure, and 2 or higher indicates
a specific reason as listed in the source code by the corresponding
set_code line. Examples:
Tones Binary Decimal Meaning
- - - - - - - - - - - - - - - - - - - -
low 0 0 passed
low high 01 1 failed
low high low 010 2 error 2
--
Shay Green <gblargg@gmail.com>

Some files were not shown because too many files have changed in this diff Show More