diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml
index 942e3e8..6c4e357 100644
--- a/.idea/dictionaries/project.xml
+++ b/.idea/dictionaries/project.xml
@@ -7,6 +7,7 @@
addsp
dechl
inchl
+ instrs
jpcc
jphl
jrcc
diff --git a/boot/agb.bin b/boot/agb.bin
new file mode 100644
index 0000000..4d38be5
Binary files /dev/null and b/boot/agb.bin differ
diff --git a/boot/agb.sym b/boot/agb.sym
new file mode 100644
index 0000000..cc4e5ca
--- /dev/null
+++ b/boot/agb.sym
@@ -0,0 +1,176 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:0008 ClearLogoGDMA
+BOOT:000d ClearLogoGDMA.end
+BOOT:000d ClearLogoTilesGDMA
+BOOT:0012 OverrideColors
+BOOT:0042 LogoTopHalf
+BOOT:005a LogoBottomHalf
+BOOT:0072 RTile
+BOOT:007a RTile.end
+BOOT:007a LogoTilemapChecksums
+BOOT:007c LogoTilemapChecksums.end
+BOOT:007c Setup
+BOOT:0093 Setup.clearOAM
+BOOT:009e Setup.processLogo
+BOOT:00b2 Setup.copyRTile
+BOOT:00d8 Setup.checkLogo
+BOOT:00db Setup.logoFailure
+BOOT:00e7 Setup.computeChecksum
+BOOT:00ed Setup.checksumFailure
+BOOT:00f5 Setup.done
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+BOOT:0200 ClearVRAM
+BOOT:0203 ClearUntilMemBoundary
+BOOT:0204 ClearUntilMemBoundary.loop
+BOOT:020a Memcpy
+BOOT:0211 WaitVBlank
+BOOT:0217 WaitVBlank.wait
+BOOT:021d PollJoypad
+BOOT:024a SetOBJAndBGPals
+BOOT:0252 SetOBJAndBGPals.writeOBJPalData
+BOOT:025c SetOBJAndBGPals.writeBGPalData
+BOOT:0262 CommitBGPalettes
+BOOT:0275 SetupSound
+BOOT:028b SetupSound.initWaveRAM
+BOOT:0291 DoLogoAnimation
+BOOT:02a5 DoLogoAnimation.writeNintendoLogoMap
+BOOT:02b0 DoLogoAnimation.dontWriteNintendoLogo
+BOOT:02d3 DoLogoAnimation.changePaletteRow
+BOOT:02d5 DoLogoAnimation.changePaletteBlock
+BOOT:02d7 DoLogoAnimation.changePaletteLoop
+BOOT:02f1 DoLogoAnimation.dontWriteLogoAttrMap
+BOOT:02ff DoLogoAnimation.playSFX
+BOOT:0306 DoLogoAnimation.dontAnimateLogo
+BOOT:0306 DoLogoAnimation.dontPlaySFX
+BOOT:0317 DoLogoAnimation.stepAnimation
+BOOT:031c PerformFadeout
+BOOT:031e PerformFadeout.loop
+BOOT:033e PerformFadeout.clearLogoArea
+BOOT:0341 PerformFadeout.clearLogoTiles
+BOOT:034a PerformFadeout.fadePalettes
+BOOT:0352 PerformFadeout.fadeColor
+BOOT:035a PerformFadeout.redCap
+BOOT:036e PerformFadeout.greenCap
+BOOT:0384 PerformFadeout.blueCap
+BOOT:038f DecodeLogoHalf
+BOOT:0391 DecodeLogoHalf.decodeTileQuarter
+BOOT:039a DecodeLogoHalf.decodingLeftHalf
+BOOT:03a8 DecodeLogoHalf.decodingRightHalf
+BOOT:03bd DecodeLogoHalf.goToRightHalf
+BOOT:03bf DecodeLogoHalf.decodingTopHalf
+BOOT:03c6 DecompressFirstNibble
+BOOT:03c7 DecompressSecondNibble
+BOOT:03ca DecompressSecondNibble.decompressBit
+BOOT:03da WriteLogoTilemap
+BOOT:03e2 WriteLogoTilemap.writeRow
+BOOT:03e4 WriteLogoTilemap.writeByte
+BOOT:03ef WriteLogoTilemap.done
+BOOT:03f0 SetupGameBoyLogo
+BOOT:03ff SetupGameBoyLogo.copyLogoRow
+BOOT:041e SetupGameBoyLogo.copyRTile
+BOOT:042c SetupGameBoyLogo.writeAttrRow
+BOOT:042e SetupGameBoyLogo.writeAttrByte
+BOOT:0441 SetupGameBoyLogo.writeTilemapByte
+BOOT:0449 SetupGameBoyLogo.notFirstRow
+BOOT:0450 SetupGameBoyLogo.notSecondRow
+BOOT:045c SetupGameBoyLogo.initBGPalsLoop
+BOOT:0488 SetupGameBoyLogo.usingOldLicensee
+BOOT:048c SetupGameBoyLogo.checkMadeByNintendo
+BOOT:0495 SetupGameBoyLogo.checksumTitle
+BOOT:04a3 SetupGameBoyLogo.seekTitleChecksum
+BOOT:04af SetupGameBoyLogo.foundTitleChecksum
+BOOT:04bb SetupGameBoyLogo.seekFourthLetter
+BOOT:04ce SetupGameBoyLogo.useDefaultIndex
+BOOT:04d0 SetupGameBoyLogo.gotIndex
+BOOT:04e9 WriteShuffledPalTriplets
+BOOT:04f5 WriteShuffledPalTriplets.get3Indexes
+BOOT:04fb WriteShuffledPalTriplets.bit0Set
+BOOT:0501 WriteShuffledPalTriplets.cancelBit0Set
+BOOT:0507 WriteShuffledPalTriplets.bit1Set
+BOOT:050f WriteShuffledPalTriplets.cancelBit1Set
+BOOT:0518 WriteShuffledPalTriplets.bit2Reset
+BOOT:0528 ApplyPaletteOverride
+BOOT:0539 ApplyPaletteOverride.copyPalette
+BOOT:0564 GetPalettes
+BOOT:0566 GetPalettes.copyPalette
+BOOT:057b AddPalTripletOffset
+BOOT:0582 AddPalTripletOffset.loop
+BOOT:0588 AddPalTripletOffset.done
+BOOT:0589 PickDMGPalette
+BOOT:0596 PickDMGPalette.seekButtonCombo
+BOOT:05a0 PickDMGPalette.jumpToDone
+BOOT:05a2 PickDMGPalette.buttonComboFound
+BOOT:05cf PickDMGPalette.done
+BOOT:05d0 SetupCompatibility
+BOOT:05de SetupCompatibility.dmgMode
+BOOT:05fe SetupCompatibility.tryWriteLogoTilemap
+BOOT:0606 SetupCompatibility.done
+BOOT:0607 GameBoyLogoTiles
+BOOT:06c7 GameBoyLogoTiles.end
+BOOT:06c7 TitleChecksums
+BOOT:0708 TitleChecksums.ambiguous
+BOOT:0716 TitleChecksums.end
+BOOT:0716 TitleFourthLetters
+BOOT:0724 TitleFourthLetters.row
+BOOT:0733 TitleFourthLetters.end
+BOOT:0733 PalTripletIDsAndFlags
+BOOT:0791 PaletteOffsets
+BOOT:07e8 Palettes
+BOOT:08d8 BootAnimationColors
+BOOT:08e4 BootAnimationColors.end
+BOOT:08e4 JoypadCombos
+BOOT:08f0 JoypadCombos.end
+BOOT:08f0 JoypadCombosTripletIDsAndFlags
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vTileMap
+00:98c2 vGameBoyLogoMap
+00:9904 vBigNintendoLogoMap
+00:99a7 vNintendoLogoMap
+01:8000 vTiles
+01:8080 vGameBoyLogoTiles
+01:8380 vNintendoLogoTiles
+01:83e0 vSecondRTile
+01:83f0 vNintendoLogoTilesEnd
+01:9800 vAttrMap
+01:98c2 vGameBoyLogoAttrs
+01:9904 vBigNintendoLogoAttrs
+01:99a7 vNintendoLogoAttrs
+02:d000 wWorkRAM
+02:d000 wTitleChecksum
+02:d002 wPreventTerminationCounter
+02:d003 wHeldButtons
+02:d004 wPressedButtons
+02:d005 wPaletteOverrideIndex
+02:d006 wWhichPalTripletCopy
+02:d007 wOldWhichPalTriplet
+02:d008 wWhichPalTriplet
+02:d009 wPalShufflingFlagsCopy
+02:d00a wOldPalShufflingFlags
+02:d00b wPalShufflingFlags
+02:d300 wZeroBuffer
+02:d800 wOBJPalBuffer
+02:d840 wOBJPalBuffer.end
+02:d840 wBGPalBuffer
+02:d880 wBGPalBuffer.end
+02:d900 wPalOfsBuffer
+02:d95a wPalOfsBuffer.end
+02:d960 wPalOfsBuffer.realEnd
+02:da00 wPalBuffer
+00:ff80 hLogoBuffer
+00:fffe hStackBottom
diff --git a/boot/agb0.bin b/boot/agb0.bin
new file mode 100644
index 0000000..e1bfe5d
Binary files /dev/null and b/boot/agb0.bin differ
diff --git a/boot/agb0.sym b/boot/agb0.sym
new file mode 100644
index 0000000..cc4e5ca
--- /dev/null
+++ b/boot/agb0.sym
@@ -0,0 +1,176 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:0008 ClearLogoGDMA
+BOOT:000d ClearLogoGDMA.end
+BOOT:000d ClearLogoTilesGDMA
+BOOT:0012 OverrideColors
+BOOT:0042 LogoTopHalf
+BOOT:005a LogoBottomHalf
+BOOT:0072 RTile
+BOOT:007a RTile.end
+BOOT:007a LogoTilemapChecksums
+BOOT:007c LogoTilemapChecksums.end
+BOOT:007c Setup
+BOOT:0093 Setup.clearOAM
+BOOT:009e Setup.processLogo
+BOOT:00b2 Setup.copyRTile
+BOOT:00d8 Setup.checkLogo
+BOOT:00db Setup.logoFailure
+BOOT:00e7 Setup.computeChecksum
+BOOT:00ed Setup.checksumFailure
+BOOT:00f5 Setup.done
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+BOOT:0200 ClearVRAM
+BOOT:0203 ClearUntilMemBoundary
+BOOT:0204 ClearUntilMemBoundary.loop
+BOOT:020a Memcpy
+BOOT:0211 WaitVBlank
+BOOT:0217 WaitVBlank.wait
+BOOT:021d PollJoypad
+BOOT:024a SetOBJAndBGPals
+BOOT:0252 SetOBJAndBGPals.writeOBJPalData
+BOOT:025c SetOBJAndBGPals.writeBGPalData
+BOOT:0262 CommitBGPalettes
+BOOT:0275 SetupSound
+BOOT:028b SetupSound.initWaveRAM
+BOOT:0291 DoLogoAnimation
+BOOT:02a5 DoLogoAnimation.writeNintendoLogoMap
+BOOT:02b0 DoLogoAnimation.dontWriteNintendoLogo
+BOOT:02d3 DoLogoAnimation.changePaletteRow
+BOOT:02d5 DoLogoAnimation.changePaletteBlock
+BOOT:02d7 DoLogoAnimation.changePaletteLoop
+BOOT:02f1 DoLogoAnimation.dontWriteLogoAttrMap
+BOOT:02ff DoLogoAnimation.playSFX
+BOOT:0306 DoLogoAnimation.dontAnimateLogo
+BOOT:0306 DoLogoAnimation.dontPlaySFX
+BOOT:0317 DoLogoAnimation.stepAnimation
+BOOT:031c PerformFadeout
+BOOT:031e PerformFadeout.loop
+BOOT:033e PerformFadeout.clearLogoArea
+BOOT:0341 PerformFadeout.clearLogoTiles
+BOOT:034a PerformFadeout.fadePalettes
+BOOT:0352 PerformFadeout.fadeColor
+BOOT:035a PerformFadeout.redCap
+BOOT:036e PerformFadeout.greenCap
+BOOT:0384 PerformFadeout.blueCap
+BOOT:038f DecodeLogoHalf
+BOOT:0391 DecodeLogoHalf.decodeTileQuarter
+BOOT:039a DecodeLogoHalf.decodingLeftHalf
+BOOT:03a8 DecodeLogoHalf.decodingRightHalf
+BOOT:03bd DecodeLogoHalf.goToRightHalf
+BOOT:03bf DecodeLogoHalf.decodingTopHalf
+BOOT:03c6 DecompressFirstNibble
+BOOT:03c7 DecompressSecondNibble
+BOOT:03ca DecompressSecondNibble.decompressBit
+BOOT:03da WriteLogoTilemap
+BOOT:03e2 WriteLogoTilemap.writeRow
+BOOT:03e4 WriteLogoTilemap.writeByte
+BOOT:03ef WriteLogoTilemap.done
+BOOT:03f0 SetupGameBoyLogo
+BOOT:03ff SetupGameBoyLogo.copyLogoRow
+BOOT:041e SetupGameBoyLogo.copyRTile
+BOOT:042c SetupGameBoyLogo.writeAttrRow
+BOOT:042e SetupGameBoyLogo.writeAttrByte
+BOOT:0441 SetupGameBoyLogo.writeTilemapByte
+BOOT:0449 SetupGameBoyLogo.notFirstRow
+BOOT:0450 SetupGameBoyLogo.notSecondRow
+BOOT:045c SetupGameBoyLogo.initBGPalsLoop
+BOOT:0488 SetupGameBoyLogo.usingOldLicensee
+BOOT:048c SetupGameBoyLogo.checkMadeByNintendo
+BOOT:0495 SetupGameBoyLogo.checksumTitle
+BOOT:04a3 SetupGameBoyLogo.seekTitleChecksum
+BOOT:04af SetupGameBoyLogo.foundTitleChecksum
+BOOT:04bb SetupGameBoyLogo.seekFourthLetter
+BOOT:04ce SetupGameBoyLogo.useDefaultIndex
+BOOT:04d0 SetupGameBoyLogo.gotIndex
+BOOT:04e9 WriteShuffledPalTriplets
+BOOT:04f5 WriteShuffledPalTriplets.get3Indexes
+BOOT:04fb WriteShuffledPalTriplets.bit0Set
+BOOT:0501 WriteShuffledPalTriplets.cancelBit0Set
+BOOT:0507 WriteShuffledPalTriplets.bit1Set
+BOOT:050f WriteShuffledPalTriplets.cancelBit1Set
+BOOT:0518 WriteShuffledPalTriplets.bit2Reset
+BOOT:0528 ApplyPaletteOverride
+BOOT:0539 ApplyPaletteOverride.copyPalette
+BOOT:0564 GetPalettes
+BOOT:0566 GetPalettes.copyPalette
+BOOT:057b AddPalTripletOffset
+BOOT:0582 AddPalTripletOffset.loop
+BOOT:0588 AddPalTripletOffset.done
+BOOT:0589 PickDMGPalette
+BOOT:0596 PickDMGPalette.seekButtonCombo
+BOOT:05a0 PickDMGPalette.jumpToDone
+BOOT:05a2 PickDMGPalette.buttonComboFound
+BOOT:05cf PickDMGPalette.done
+BOOT:05d0 SetupCompatibility
+BOOT:05de SetupCompatibility.dmgMode
+BOOT:05fe SetupCompatibility.tryWriteLogoTilemap
+BOOT:0606 SetupCompatibility.done
+BOOT:0607 GameBoyLogoTiles
+BOOT:06c7 GameBoyLogoTiles.end
+BOOT:06c7 TitleChecksums
+BOOT:0708 TitleChecksums.ambiguous
+BOOT:0716 TitleChecksums.end
+BOOT:0716 TitleFourthLetters
+BOOT:0724 TitleFourthLetters.row
+BOOT:0733 TitleFourthLetters.end
+BOOT:0733 PalTripletIDsAndFlags
+BOOT:0791 PaletteOffsets
+BOOT:07e8 Palettes
+BOOT:08d8 BootAnimationColors
+BOOT:08e4 BootAnimationColors.end
+BOOT:08e4 JoypadCombos
+BOOT:08f0 JoypadCombos.end
+BOOT:08f0 JoypadCombosTripletIDsAndFlags
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vTileMap
+00:98c2 vGameBoyLogoMap
+00:9904 vBigNintendoLogoMap
+00:99a7 vNintendoLogoMap
+01:8000 vTiles
+01:8080 vGameBoyLogoTiles
+01:8380 vNintendoLogoTiles
+01:83e0 vSecondRTile
+01:83f0 vNintendoLogoTilesEnd
+01:9800 vAttrMap
+01:98c2 vGameBoyLogoAttrs
+01:9904 vBigNintendoLogoAttrs
+01:99a7 vNintendoLogoAttrs
+02:d000 wWorkRAM
+02:d000 wTitleChecksum
+02:d002 wPreventTerminationCounter
+02:d003 wHeldButtons
+02:d004 wPressedButtons
+02:d005 wPaletteOverrideIndex
+02:d006 wWhichPalTripletCopy
+02:d007 wOldWhichPalTriplet
+02:d008 wWhichPalTriplet
+02:d009 wPalShufflingFlagsCopy
+02:d00a wOldPalShufflingFlags
+02:d00b wPalShufflingFlags
+02:d300 wZeroBuffer
+02:d800 wOBJPalBuffer
+02:d840 wOBJPalBuffer.end
+02:d840 wBGPalBuffer
+02:d880 wBGPalBuffer.end
+02:d900 wPalOfsBuffer
+02:d95a wPalOfsBuffer.end
+02:d960 wPalOfsBuffer.realEnd
+02:da00 wPalBuffer
+00:ff80 hLogoBuffer
+00:fffe hStackBottom
diff --git a/boot/cgb.bin b/boot/cgb.bin
new file mode 100644
index 0000000..7368ee9
Binary files /dev/null and b/boot/cgb.bin differ
diff --git a/boot/cgb.sym b/boot/cgb.sym
new file mode 100644
index 0000000..46c0809
--- /dev/null
+++ b/boot/cgb.sym
@@ -0,0 +1,176 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:0008 ClearLogoGDMA
+BOOT:000d ClearLogoGDMA.end
+BOOT:000d ClearLogoTilesGDMA
+BOOT:0012 OverrideColors
+BOOT:0042 LogoTopHalf
+BOOT:005a LogoBottomHalf
+BOOT:0072 RTile
+BOOT:007a RTile.end
+BOOT:007a LogoTilemapChecksums
+BOOT:007c LogoTilemapChecksums.end
+BOOT:007c Setup
+BOOT:0093 Setup.clearOAM
+BOOT:009e Setup.processLogo
+BOOT:00b2 Setup.copyRTile
+BOOT:00d8 Setup.checkLogo
+BOOT:00db Setup.logoFailure
+BOOT:00e7 Setup.computeChecksum
+BOOT:00ed Setup.checksumFailure
+BOOT:00f6 Setup.done
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+BOOT:0200 ClearVRAM
+BOOT:0203 ClearUntilMemBoundary
+BOOT:0204 ClearUntilMemBoundary.loop
+BOOT:020a Memcpy
+BOOT:0211 WaitVBlank
+BOOT:0217 WaitVBlank.wait
+BOOT:021d PollJoypad
+BOOT:024a SetOBJAndBGPals
+BOOT:0252 SetOBJAndBGPals.writeOBJPalData
+BOOT:025c SetOBJAndBGPals.writeBGPalData
+BOOT:0262 CommitBGPalettes
+BOOT:0275 SetupSound
+BOOT:028b SetupSound.initWaveRAM
+BOOT:0291 DoLogoAnimation
+BOOT:02a5 DoLogoAnimation.writeNintendoLogoMap
+BOOT:02b0 DoLogoAnimation.dontWriteNintendoLogo
+BOOT:02d3 DoLogoAnimation.changePaletteRow
+BOOT:02d5 DoLogoAnimation.changePaletteBlock
+BOOT:02d7 DoLogoAnimation.changePaletteLoop
+BOOT:02f1 DoLogoAnimation.dontWriteLogoAttrMap
+BOOT:02ff DoLogoAnimation.playSFX
+BOOT:0306 DoLogoAnimation.dontAnimateLogo
+BOOT:0306 DoLogoAnimation.dontPlaySFX
+BOOT:0317 DoLogoAnimation.stepAnimation
+BOOT:031c PerformFadeout
+BOOT:031e PerformFadeout.loop
+BOOT:033e PerformFadeout.clearLogoArea
+BOOT:0341 PerformFadeout.clearLogoTiles
+BOOT:034a PerformFadeout.fadePalettes
+BOOT:0352 PerformFadeout.fadeColor
+BOOT:035a PerformFadeout.redCap
+BOOT:036e PerformFadeout.greenCap
+BOOT:0384 PerformFadeout.blueCap
+BOOT:038f DecodeLogoHalf
+BOOT:0391 DecodeLogoHalf.decodeTileQuarter
+BOOT:039a DecodeLogoHalf.decodingLeftHalf
+BOOT:03a8 DecodeLogoHalf.decodingRightHalf
+BOOT:03bd DecodeLogoHalf.goToRightHalf
+BOOT:03bf DecodeLogoHalf.decodingTopHalf
+BOOT:03c6 DecompressFirstNibble
+BOOT:03c7 DecompressSecondNibble
+BOOT:03ca DecompressSecondNibble.decompressBit
+BOOT:03da WriteLogoTilemap
+BOOT:03e2 WriteLogoTilemap.writeRow
+BOOT:03e4 WriteLogoTilemap.writeByte
+BOOT:03ef WriteLogoTilemap.done
+BOOT:03f0 SetupGameBoyLogo
+BOOT:03ff SetupGameBoyLogo.copyLogoRow
+BOOT:041e SetupGameBoyLogo.copyRTile
+BOOT:042c SetupGameBoyLogo.writeAttrRow
+BOOT:042e SetupGameBoyLogo.writeAttrByte
+BOOT:0441 SetupGameBoyLogo.writeTilemapByte
+BOOT:0449 SetupGameBoyLogo.notFirstRow
+BOOT:0450 SetupGameBoyLogo.notSecondRow
+BOOT:045c SetupGameBoyLogo.initBGPalsLoop
+BOOT:0488 SetupGameBoyLogo.usingOldLicensee
+BOOT:048c SetupGameBoyLogo.checkMadeByNintendo
+BOOT:0495 SetupGameBoyLogo.checksumTitle
+BOOT:04a3 SetupGameBoyLogo.seekTitleChecksum
+BOOT:04af SetupGameBoyLogo.foundTitleChecksum
+BOOT:04bb SetupGameBoyLogo.seekFourthLetter
+BOOT:04ce SetupGameBoyLogo.useDefaultIndex
+BOOT:04d0 SetupGameBoyLogo.gotIndex
+BOOT:04e9 WriteShuffledPalTriplets
+BOOT:04f5 WriteShuffledPalTriplets.get3Indexes
+BOOT:04fb WriteShuffledPalTriplets.bit0Set
+BOOT:0501 WriteShuffledPalTriplets.cancelBit0Set
+BOOT:0507 WriteShuffledPalTriplets.bit1Set
+BOOT:050f WriteShuffledPalTriplets.cancelBit1Set
+BOOT:0518 WriteShuffledPalTriplets.bit2Reset
+BOOT:0528 ApplyPaletteOverride
+BOOT:0539 ApplyPaletteOverride.copyPalette
+BOOT:0564 GetPalettes
+BOOT:0566 GetPalettes.copyPalette
+BOOT:057b AddPalTripletOffset
+BOOT:0582 AddPalTripletOffset.loop
+BOOT:0588 AddPalTripletOffset.done
+BOOT:0589 PickDMGPalette
+BOOT:0596 PickDMGPalette.seekButtonCombo
+BOOT:05a0 PickDMGPalette.jumpToDone
+BOOT:05a2 PickDMGPalette.buttonComboFound
+BOOT:05cf PickDMGPalette.done
+BOOT:05d0 SetupCompatibility
+BOOT:05de SetupCompatibility.dmgMode
+BOOT:05fe SetupCompatibility.tryWriteLogoTilemap
+BOOT:0606 SetupCompatibility.done
+BOOT:0607 GameBoyLogoTiles
+BOOT:06c7 GameBoyLogoTiles.end
+BOOT:06c7 TitleChecksums
+BOOT:0708 TitleChecksums.ambiguous
+BOOT:0716 TitleChecksums.end
+BOOT:0716 TitleFourthLetters
+BOOT:0724 TitleFourthLetters.row
+BOOT:0733 TitleFourthLetters.end
+BOOT:0733 PalTripletIDsAndFlags
+BOOT:0791 PaletteOffsets
+BOOT:07e8 Palettes
+BOOT:08d8 BootAnimationColors
+BOOT:08e4 BootAnimationColors.end
+BOOT:08e4 JoypadCombos
+BOOT:08f0 JoypadCombos.end
+BOOT:08f0 JoypadCombosTripletIDsAndFlags
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vTileMap
+00:98c2 vGameBoyLogoMap
+00:9904 vBigNintendoLogoMap
+00:99a7 vNintendoLogoMap
+01:8000 vTiles
+01:8080 vGameBoyLogoTiles
+01:8380 vNintendoLogoTiles
+01:83e0 vSecondRTile
+01:83f0 vNintendoLogoTilesEnd
+01:9800 vAttrMap
+01:98c2 vGameBoyLogoAttrs
+01:9904 vBigNintendoLogoAttrs
+01:99a7 vNintendoLogoAttrs
+02:d000 wWorkRAM
+02:d000 wTitleChecksum
+02:d002 wPreventTerminationCounter
+02:d003 wHeldButtons
+02:d004 wPressedButtons
+02:d005 wPaletteOverrideIndex
+02:d006 wWhichPalTripletCopy
+02:d007 wOldWhichPalTriplet
+02:d008 wWhichPalTriplet
+02:d009 wPalShufflingFlagsCopy
+02:d00a wOldPalShufflingFlags
+02:d00b wPalShufflingFlags
+02:d300 wZeroBuffer
+02:d800 wOBJPalBuffer
+02:d840 wOBJPalBuffer.end
+02:d840 wBGPalBuffer
+02:d880 wBGPalBuffer.end
+02:d900 wPalOfsBuffer
+02:d95a wPalOfsBuffer.end
+02:d960 wPalOfsBuffer.realEnd
+02:da00 wPalBuffer
+00:ff80 hLogoBuffer
+00:fffe hStackBottom
diff --git a/boot/cgb0.bin b/boot/cgb0.bin
new file mode 100644
index 0000000..c72d4f9
Binary files /dev/null and b/boot/cgb0.bin differ
diff --git a/boot/cgb0.sym b/boot/cgb0.sym
new file mode 100644
index 0000000..b0463db
--- /dev/null
+++ b/boot/cgb0.sym
@@ -0,0 +1,176 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:0008 ClearLogoGDMA
+BOOT:000d ClearLogoGDMA.end
+BOOT:000d ClearLogoTilesGDMA
+BOOT:0012 OverrideColors
+BOOT:0042 LogoTopHalf
+BOOT:005a LogoBottomHalf
+BOOT:0072 RTile
+BOOT:007a RTile.end
+BOOT:007a LogoTilemapChecksums
+BOOT:007c LogoTilemapChecksums.end
+BOOT:007c Setup
+BOOT:0093 Setup.clearOAM
+BOOT:009e Setup.processLogo
+BOOT:00b2 Setup.copyRTile
+BOOT:00d8 Setup.checkLogo
+BOOT:00db Setup.logoFailure
+BOOT:00e7 Setup.computeChecksum
+BOOT:00ed Setup.checksumFailure
+BOOT:00f6 Setup.done
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+BOOT:0200 ClearVRAM
+BOOT:0203 ClearUntilMemBoundary
+BOOT:0204 ClearUntilMemBoundary.loop
+BOOT:020a Memcpy
+BOOT:0211 WaitVBlank
+BOOT:0217 WaitVBlank.wait
+BOOT:021d PollJoypad
+BOOT:024a SetOBJAndBGPals
+BOOT:0252 SetOBJAndBGPals.writeOBJPalData
+BOOT:025c SetOBJAndBGPals.writeBGPalData
+BOOT:0262 CommitBGPalettes
+BOOT:0275 SetupSound
+BOOT:0286 DoLogoAnimation
+BOOT:029a DoLogoAnimation.writeNintendoLogoMap
+BOOT:02a5 DoLogoAnimation.dontWriteNintendoLogo
+BOOT:02c8 DoLogoAnimation.changePaletteRow
+BOOT:02ca DoLogoAnimation.changePaletteBlock
+BOOT:02cc DoLogoAnimation.changePaletteLoop
+BOOT:02e6 DoLogoAnimation.dontWriteLogoAttrMap
+BOOT:02f4 DoLogoAnimation.playSFX
+BOOT:02fb DoLogoAnimation.dontAnimateLogo
+BOOT:02fb DoLogoAnimation.dontPlaySFX
+BOOT:030c DoLogoAnimation.stepAnimation
+BOOT:0311 PerformFadeout
+BOOT:0313 PerformFadeout.loop
+BOOT:0333 PerformFadeout.clearLogoArea
+BOOT:0336 PerformFadeout.clearLogoTiles
+BOOT:033f PerformFadeout.fadePalettes
+BOOT:0347 PerformFadeout.fadeColor
+BOOT:034f PerformFadeout.redCap
+BOOT:0363 PerformFadeout.greenCap
+BOOT:0379 PerformFadeout.blueCap
+BOOT:0384 DecodeLogoHalf
+BOOT:0386 DecodeLogoHalf.decodeTileQuarter
+BOOT:038f DecodeLogoHalf.decodingLeftHalf
+BOOT:039d DecodeLogoHalf.decodingRightHalf
+BOOT:03b2 DecodeLogoHalf.goToRightHalf
+BOOT:03b4 DecodeLogoHalf.decodingTopHalf
+BOOT:03bb DecompressFirstNibble
+BOOT:03bc DecompressSecondNibble
+BOOT:03bf DecompressSecondNibble.decompressBit
+BOOT:03cf WriteLogoTilemap
+BOOT:03d7 WriteLogoTilemap.writeRow
+BOOT:03d9 WriteLogoTilemap.writeByte
+BOOT:03e4 WriteLogoTilemap.done
+BOOT:03e5 SetupGameBoyLogo
+BOOT:03f4 SetupGameBoyLogo.copyLogoTile
+BOOT:03f6 SetupGameBoyLogo.copyLogoRow
+BOOT:0418 SetupGameBoyLogo.copyRTile
+BOOT:0426 SetupGameBoyLogo.writeAttrRow
+BOOT:0428 SetupGameBoyLogo.writeAttrByte
+BOOT:043b SetupGameBoyLogo.writeTilemapByte
+BOOT:0443 SetupGameBoyLogo.notFirstRow
+BOOT:044a SetupGameBoyLogo.notSecondRow
+BOOT:0456 SetupGameBoyLogo.initBGPalsLoop
+BOOT:0482 SetupGameBoyLogo.usingOldLicensee
+BOOT:0486 SetupGameBoyLogo.checkMadeByNintendo
+BOOT:048f SetupGameBoyLogo.checksumTitle
+BOOT:049d SetupGameBoyLogo.seekTitleChecksum
+BOOT:04a9 SetupGameBoyLogo.foundTitleChecksum
+BOOT:04b5 SetupGameBoyLogo.seekFourthLetter
+BOOT:04c8 SetupGameBoyLogo.useDefaultIndex
+BOOT:04ca SetupGameBoyLogo.gotIndex
+BOOT:04e9 WriteShuffledPalTriplets
+BOOT:04f5 WriteShuffledPalTriplets.get3Indexes
+BOOT:04fb WriteShuffledPalTriplets.bit0Set
+BOOT:0501 WriteShuffledPalTriplets.cancelBit0Set
+BOOT:0507 WriteShuffledPalTriplets.bit1Set
+BOOT:050f WriteShuffledPalTriplets.cancelBit1Set
+BOOT:0518 WriteShuffledPalTriplets.bit2Reset
+BOOT:0528 ApplyPaletteOverride
+BOOT:0539 ApplyPaletteOverride.copyPalette
+BOOT:0564 GetPalettes
+BOOT:0566 GetPalettes.copyPalette
+BOOT:057b AddPalTripletOffset
+BOOT:0582 AddPalTripletOffset.loop
+BOOT:0588 AddPalTripletOffset.done
+BOOT:0589 PickDMGPalette
+BOOT:0596 PickDMGPalette.seekButtonCombo
+BOOT:05a0 PickDMGPalette.jumpToDone
+BOOT:05a2 PickDMGPalette.buttonComboFound
+BOOT:05cf PickDMGPalette.done
+BOOT:05d0 SetupCompatibility
+BOOT:05de SetupCompatibility.dmgMode
+BOOT:05fe SetupCompatibility.tryWriteLogoTilemap
+BOOT:0606 SetupCompatibility.done
+BOOT:0607 GameBoyLogoTiles
+BOOT:06c7 GameBoyLogoTiles.end
+BOOT:06c7 TitleChecksums
+BOOT:0708 TitleChecksums.ambiguous
+BOOT:0716 TitleChecksums.end
+BOOT:0716 TitleFourthLetters
+BOOT:0724 TitleFourthLetters.row
+BOOT:0733 TitleFourthLetters.end
+BOOT:0733 PalTripletIDsAndFlags
+BOOT:0791 PaletteOffsets
+BOOT:07e8 Palettes
+BOOT:08d8 BootAnimationColors
+BOOT:08e4 BootAnimationColors.end
+BOOT:08e4 JoypadCombos
+BOOT:08f0 JoypadCombos.end
+BOOT:08f0 JoypadCombosTripletIDsAndFlags
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vTileMap
+00:98c2 vGameBoyLogoMap
+00:9904 vBigNintendoLogoMap
+00:99a7 vNintendoLogoMap
+01:8000 vTiles
+01:8080 vGameBoyLogoTiles
+01:8380 vNintendoLogoTiles
+01:83e0 vSecondRTile
+01:83f0 vNintendoLogoTilesEnd
+01:9800 vAttrMap
+01:98c2 vGameBoyLogoAttrs
+01:9904 vBigNintendoLogoAttrs
+01:99a7 vNintendoLogoAttrs
+02:d000 wWorkRAM
+02:d000 wTitleChecksum
+02:d002 wPreventTerminationCounter
+02:d003 wHeldButtons
+02:d004 wPressedButtons
+02:d005 wPaletteOverrideIndex
+02:d006 wWhichPalTripletCopy
+02:d007 wOldWhichPalTriplet
+02:d008 wWhichPalTriplet
+02:d009 wPalShufflingFlagsCopy
+02:d00a wOldPalShufflingFlags
+02:d00b wPalShufflingFlags
+02:d300 wZeroBuffer
+02:d800 wOBJPalBuffer
+02:d840 wOBJPalBuffer.end
+02:d840 wBGPalBuffer
+02:d880 wBGPalBuffer.end
+02:d900 wPalOfsBuffer
+02:d95a wPalOfsBuffer.end
+02:d960 wPalOfsBuffer.realEnd
+02:da00 wPalBuffer
+00:ff80 hLogoBuffer
+00:fffe hStackBottom
diff --git a/boot/cgbE.bin b/boot/cgbE.bin
new file mode 100644
index 0000000..3a66fac
Binary files /dev/null and b/boot/cgbE.bin differ
diff --git a/boot/cgbE.sym b/boot/cgbE.sym
new file mode 100644
index 0000000..46c0809
--- /dev/null
+++ b/boot/cgbE.sym
@@ -0,0 +1,176 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:0008 ClearLogoGDMA
+BOOT:000d ClearLogoGDMA.end
+BOOT:000d ClearLogoTilesGDMA
+BOOT:0012 OverrideColors
+BOOT:0042 LogoTopHalf
+BOOT:005a LogoBottomHalf
+BOOT:0072 RTile
+BOOT:007a RTile.end
+BOOT:007a LogoTilemapChecksums
+BOOT:007c LogoTilemapChecksums.end
+BOOT:007c Setup
+BOOT:0093 Setup.clearOAM
+BOOT:009e Setup.processLogo
+BOOT:00b2 Setup.copyRTile
+BOOT:00d8 Setup.checkLogo
+BOOT:00db Setup.logoFailure
+BOOT:00e7 Setup.computeChecksum
+BOOT:00ed Setup.checksumFailure
+BOOT:00f6 Setup.done
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+BOOT:0200 ClearVRAM
+BOOT:0203 ClearUntilMemBoundary
+BOOT:0204 ClearUntilMemBoundary.loop
+BOOT:020a Memcpy
+BOOT:0211 WaitVBlank
+BOOT:0217 WaitVBlank.wait
+BOOT:021d PollJoypad
+BOOT:024a SetOBJAndBGPals
+BOOT:0252 SetOBJAndBGPals.writeOBJPalData
+BOOT:025c SetOBJAndBGPals.writeBGPalData
+BOOT:0262 CommitBGPalettes
+BOOT:0275 SetupSound
+BOOT:028b SetupSound.initWaveRAM
+BOOT:0291 DoLogoAnimation
+BOOT:02a5 DoLogoAnimation.writeNintendoLogoMap
+BOOT:02b0 DoLogoAnimation.dontWriteNintendoLogo
+BOOT:02d3 DoLogoAnimation.changePaletteRow
+BOOT:02d5 DoLogoAnimation.changePaletteBlock
+BOOT:02d7 DoLogoAnimation.changePaletteLoop
+BOOT:02f1 DoLogoAnimation.dontWriteLogoAttrMap
+BOOT:02ff DoLogoAnimation.playSFX
+BOOT:0306 DoLogoAnimation.dontAnimateLogo
+BOOT:0306 DoLogoAnimation.dontPlaySFX
+BOOT:0317 DoLogoAnimation.stepAnimation
+BOOT:031c PerformFadeout
+BOOT:031e PerformFadeout.loop
+BOOT:033e PerformFadeout.clearLogoArea
+BOOT:0341 PerformFadeout.clearLogoTiles
+BOOT:034a PerformFadeout.fadePalettes
+BOOT:0352 PerformFadeout.fadeColor
+BOOT:035a PerformFadeout.redCap
+BOOT:036e PerformFadeout.greenCap
+BOOT:0384 PerformFadeout.blueCap
+BOOT:038f DecodeLogoHalf
+BOOT:0391 DecodeLogoHalf.decodeTileQuarter
+BOOT:039a DecodeLogoHalf.decodingLeftHalf
+BOOT:03a8 DecodeLogoHalf.decodingRightHalf
+BOOT:03bd DecodeLogoHalf.goToRightHalf
+BOOT:03bf DecodeLogoHalf.decodingTopHalf
+BOOT:03c6 DecompressFirstNibble
+BOOT:03c7 DecompressSecondNibble
+BOOT:03ca DecompressSecondNibble.decompressBit
+BOOT:03da WriteLogoTilemap
+BOOT:03e2 WriteLogoTilemap.writeRow
+BOOT:03e4 WriteLogoTilemap.writeByte
+BOOT:03ef WriteLogoTilemap.done
+BOOT:03f0 SetupGameBoyLogo
+BOOT:03ff SetupGameBoyLogo.copyLogoRow
+BOOT:041e SetupGameBoyLogo.copyRTile
+BOOT:042c SetupGameBoyLogo.writeAttrRow
+BOOT:042e SetupGameBoyLogo.writeAttrByte
+BOOT:0441 SetupGameBoyLogo.writeTilemapByte
+BOOT:0449 SetupGameBoyLogo.notFirstRow
+BOOT:0450 SetupGameBoyLogo.notSecondRow
+BOOT:045c SetupGameBoyLogo.initBGPalsLoop
+BOOT:0488 SetupGameBoyLogo.usingOldLicensee
+BOOT:048c SetupGameBoyLogo.checkMadeByNintendo
+BOOT:0495 SetupGameBoyLogo.checksumTitle
+BOOT:04a3 SetupGameBoyLogo.seekTitleChecksum
+BOOT:04af SetupGameBoyLogo.foundTitleChecksum
+BOOT:04bb SetupGameBoyLogo.seekFourthLetter
+BOOT:04ce SetupGameBoyLogo.useDefaultIndex
+BOOT:04d0 SetupGameBoyLogo.gotIndex
+BOOT:04e9 WriteShuffledPalTriplets
+BOOT:04f5 WriteShuffledPalTriplets.get3Indexes
+BOOT:04fb WriteShuffledPalTriplets.bit0Set
+BOOT:0501 WriteShuffledPalTriplets.cancelBit0Set
+BOOT:0507 WriteShuffledPalTriplets.bit1Set
+BOOT:050f WriteShuffledPalTriplets.cancelBit1Set
+BOOT:0518 WriteShuffledPalTriplets.bit2Reset
+BOOT:0528 ApplyPaletteOverride
+BOOT:0539 ApplyPaletteOverride.copyPalette
+BOOT:0564 GetPalettes
+BOOT:0566 GetPalettes.copyPalette
+BOOT:057b AddPalTripletOffset
+BOOT:0582 AddPalTripletOffset.loop
+BOOT:0588 AddPalTripletOffset.done
+BOOT:0589 PickDMGPalette
+BOOT:0596 PickDMGPalette.seekButtonCombo
+BOOT:05a0 PickDMGPalette.jumpToDone
+BOOT:05a2 PickDMGPalette.buttonComboFound
+BOOT:05cf PickDMGPalette.done
+BOOT:05d0 SetupCompatibility
+BOOT:05de SetupCompatibility.dmgMode
+BOOT:05fe SetupCompatibility.tryWriteLogoTilemap
+BOOT:0606 SetupCompatibility.done
+BOOT:0607 GameBoyLogoTiles
+BOOT:06c7 GameBoyLogoTiles.end
+BOOT:06c7 TitleChecksums
+BOOT:0708 TitleChecksums.ambiguous
+BOOT:0716 TitleChecksums.end
+BOOT:0716 TitleFourthLetters
+BOOT:0724 TitleFourthLetters.row
+BOOT:0733 TitleFourthLetters.end
+BOOT:0733 PalTripletIDsAndFlags
+BOOT:0791 PaletteOffsets
+BOOT:07e8 Palettes
+BOOT:08d8 BootAnimationColors
+BOOT:08e4 BootAnimationColors.end
+BOOT:08e4 JoypadCombos
+BOOT:08f0 JoypadCombos.end
+BOOT:08f0 JoypadCombosTripletIDsAndFlags
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vTileMap
+00:98c2 vGameBoyLogoMap
+00:9904 vBigNintendoLogoMap
+00:99a7 vNintendoLogoMap
+01:8000 vTiles
+01:8080 vGameBoyLogoTiles
+01:8380 vNintendoLogoTiles
+01:83e0 vSecondRTile
+01:83f0 vNintendoLogoTilesEnd
+01:9800 vAttrMap
+01:98c2 vGameBoyLogoAttrs
+01:9904 vBigNintendoLogoAttrs
+01:99a7 vNintendoLogoAttrs
+02:d000 wWorkRAM
+02:d000 wTitleChecksum
+02:d002 wPreventTerminationCounter
+02:d003 wHeldButtons
+02:d004 wPressedButtons
+02:d005 wPaletteOverrideIndex
+02:d006 wWhichPalTripletCopy
+02:d007 wOldWhichPalTriplet
+02:d008 wWhichPalTriplet
+02:d009 wPalShufflingFlagsCopy
+02:d00a wOldPalShufflingFlags
+02:d00b wPalShufflingFlags
+02:d300 wZeroBuffer
+02:d800 wOBJPalBuffer
+02:d840 wOBJPalBuffer.end
+02:d840 wBGPalBuffer
+02:d880 wBGPalBuffer.end
+02:d900 wPalOfsBuffer
+02:d95a wPalOfsBuffer.end
+02:d960 wPalOfsBuffer.realEnd
+02:da00 wPalBuffer
+00:ff80 hLogoBuffer
+00:fffe hStackBottom
diff --git a/boot/dmg.bin b/boot/dmg.bin
new file mode 100644
index 0000000..afa0ee4
Binary files /dev/null and b/boot/dmg.bin differ
diff --git a/boot/dmg.sym b/boot/dmg.sym
new file mode 100644
index 0000000..d583a47
--- /dev/null
+++ b/boot/dmg.sym
@@ -0,0 +1,42 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:0007 EntryPoint.clearVRAM
+BOOT:0027 EntryPoint.decompressLogo
+BOOT:0039 EntryPoint.copyRTile
+BOOT:0048 EntryPoint.writeTilemapRow
+BOOT:004a EntryPoint.writeTilemapByte
+BOOT:0055 ScrollLogo
+BOOT:0060 ScrollLogo.loop
+BOOT:0062 ScrollLogo.delayFrames
+BOOT:0064 ScrollLogo.waitVBlank
+BOOT:0080 ScrollLogo.playSound
+BOOT:0086 ScrollLogo.dontPlaySound
+BOOT:0095 DecompressFirstNibble
+BOOT:0096 DecompressSecondNibble
+BOOT:0098 DecompressSecondNibble.loop
+BOOT:00a8 Logo
+BOOT:00d8 RTile
+BOOT:00e0 CheckLogo
+BOOT:00e6 CheckLogo.compare
+BOOT:00e9 CheckLogo.logoFailure
+BOOT:00f4 CheckLogo.computeChecksum
+BOOT:00fa CheckLogo.checksumFailure
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vMainTilemap
+00:fffe hStackBottom
diff --git a/boot/dmg0.bin b/boot/dmg0.bin
new file mode 100644
index 0000000..a558044
Binary files /dev/null and b/boot/dmg0.bin differ
diff --git a/boot/dmg0.sym b/boot/dmg0.sym
new file mode 100644
index 0000000..463d7e8
--- /dev/null
+++ b/boot/dmg0.sym
@@ -0,0 +1,40 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:0007 EntryPoint.clearVRAM
+BOOT:0028 EntryPoint.checkLogo
+BOOT:0036 EntryPoint.computeChecksum
+BOOT:0042 EntryPoint.decompressLogo
+BOOT:0054 EntryPoint.writeTilemapRow
+BOOT:0056 EntryPoint.writeTilemapByte
+BOOT:0063 ScrollLogo
+BOOT:006e ScrollLogo.loop
+BOOT:0083 ScrollLogo.playSound
+BOOT:0089 ScrollLogo.dontPlaySound
+BOOT:0098 Lockup
+BOOT:009c Lockup.loop
+BOOT:00a9 DecompressFirstNibble
+BOOT:00aa DecompressSecondNibble
+BOOT:00ac DecompressSecondNibble.loop
+BOOT:00bc DelayFrames
+BOOT:00be DelayFrames.loop
+BOOT:00cb Logo
+BOOT:00fd Done
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vMainTilemap
+00:fffe hStackBottom
diff --git a/boot/mgb.bin b/boot/mgb.bin
new file mode 100644
index 0000000..d321b04
Binary files /dev/null and b/boot/mgb.bin differ
diff --git a/boot/mgb.sym b/boot/mgb.sym
new file mode 100644
index 0000000..d583a47
--- /dev/null
+++ b/boot/mgb.sym
@@ -0,0 +1,42 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:0007 EntryPoint.clearVRAM
+BOOT:0027 EntryPoint.decompressLogo
+BOOT:0039 EntryPoint.copyRTile
+BOOT:0048 EntryPoint.writeTilemapRow
+BOOT:004a EntryPoint.writeTilemapByte
+BOOT:0055 ScrollLogo
+BOOT:0060 ScrollLogo.loop
+BOOT:0062 ScrollLogo.delayFrames
+BOOT:0064 ScrollLogo.waitVBlank
+BOOT:0080 ScrollLogo.playSound
+BOOT:0086 ScrollLogo.dontPlaySound
+BOOT:0095 DecompressFirstNibble
+BOOT:0096 DecompressSecondNibble
+BOOT:0098 DecompressSecondNibble.loop
+BOOT:00a8 Logo
+BOOT:00d8 RTile
+BOOT:00e0 CheckLogo
+BOOT:00e6 CheckLogo.compare
+BOOT:00e9 CheckLogo.logoFailure
+BOOT:00f4 CheckLogo.computeChecksum
+BOOT:00fa CheckLogo.checksumFailure
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vMainTilemap
+00:fffe hStackBottom
diff --git a/boot/sgb.bin b/boot/sgb.bin
new file mode 100644
index 0000000..2bece74
Binary files /dev/null and b/boot/sgb.bin differ
diff --git a/boot/sgb.sym b/boot/sgb.sym
new file mode 100644
index 0000000..f3f52a0
--- /dev/null
+++ b/boot/sgb.sym
@@ -0,0 +1,44 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:000b EntryPoint.clearVRAM
+BOOT:002b EntryPoint.clearBuffer
+BOOT:0036 EntryPoint.copyHeader
+BOOT:0039 EntryPoint.computeChecksum
+BOOT:0052 EntryPoint.decompressHeader
+BOOT:0064 EntryPoint.copyRTile
+BOOT:0073 EntryPoint.writeTilemapRow
+BOOT:0075 EntryPoint.writeTilemapByte
+BOOT:0080 SendData
+BOOT:0089 SendData.sendPacket
+BOOT:0091 SendData.sendByte
+BOOT:0095 SendData.sendBit
+BOOT:009d SendData.gotBit
+BOOT:00c2 Wait4Frames
+BOOT:00c4 Wait4Frames.waitVBlank
+BOOT:00cc Wait4Frames.wait
+BOOT:00d3 DecompressFirstNibble
+BOOT:00d4 DecompressSecondNibble
+BOOT:00d6 DecompressSecondNibble.decompressBit
+BOOT:00e6 RTile
+BOOT:00fc Done
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vMainTilemap
+00:c000 wBuffer
+00:c060 wBufferEnd
+00:fffe hStackBottom
diff --git a/boot/sgb2.bin b/boot/sgb2.bin
new file mode 100644
index 0000000..96d22b3
Binary files /dev/null and b/boot/sgb2.bin differ
diff --git a/boot/sgb2.sym b/boot/sgb2.sym
new file mode 100644
index 0000000..f3f52a0
--- /dev/null
+++ b/boot/sgb2.sym
@@ -0,0 +1,44 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:000b EntryPoint.clearVRAM
+BOOT:002b EntryPoint.clearBuffer
+BOOT:0036 EntryPoint.copyHeader
+BOOT:0039 EntryPoint.computeChecksum
+BOOT:0052 EntryPoint.decompressHeader
+BOOT:0064 EntryPoint.copyRTile
+BOOT:0073 EntryPoint.writeTilemapRow
+BOOT:0075 EntryPoint.writeTilemapByte
+BOOT:0080 SendData
+BOOT:0089 SendData.sendPacket
+BOOT:0091 SendData.sendByte
+BOOT:0095 SendData.sendBit
+BOOT:009d SendData.gotBit
+BOOT:00c2 Wait4Frames
+BOOT:00c4 Wait4Frames.waitVBlank
+BOOT:00cc Wait4Frames.wait
+BOOT:00d3 DecompressFirstNibble
+BOOT:00d4 DecompressSecondNibble
+BOOT:00d6 DecompressSecondNibble.decompressBit
+BOOT:00e6 RTile
+BOOT:00fc Done
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:013f HeaderMenufacturer
+BOOT:0143 HeaderCGBCompat
+BOOT:0144 HeaderNewLicensee
+BOOT:0146 HeaderSGBFlag
+BOOT:0147 HeaderCartType
+BOOT:0148 HeaderROMSize
+BOOT:0149 HeaderRAMSize
+BOOT:014a HeaderRegionCode
+BOOT:014b HeaderOldLicensee
+BOOT:014c HeaderROMVersion
+BOOT:014d HeaderChecksum
+BOOT:014e HeaderGlobalChecksum
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vMainTilemap
+00:c000 wBuffer
+00:c060 wBufferEnd
+00:fffe hStackBottom
diff --git a/boot/stadium2.bin b/boot/stadium2.bin
new file mode 100644
index 0000000..28e1271
Binary files /dev/null and b/boot/stadium2.bin differ
diff --git a/boot/stadium2.sym b/boot/stadium2.sym
new file mode 100644
index 0000000..57129fe
--- /dev/null
+++ b/boot/stadium2.sym
@@ -0,0 +1,98 @@
+; File generated by rgblink
+BOOT:0000 EntryPoint
+BOOT:000c EntryPoint.clearBGPalettes
+BOOT:0013 ClearLogoGDMA
+BOOT:0018 ClearLogoGDMAEnd
+BOOT:0018 ClearLogoTilesGDMA
+BOOT:001d RTile
+BOOT:0025 Main
+BOOT:0025 RTileEnd
+BOOT:003c Main.clearOAM
+BOOT:0047 Main.processLogo
+BOOT:005b Main.copyRTile
+BOOT:007f Main.nop
+BOOT:0084 Main.lockup
+BOOT:0086 ClearVRAM
+BOOT:0089 ClearUntilMemBoundary
+BOOT:008a ClearUntilMemBoundary.loop
+BOOT:0090 Memcpy
+BOOT:0097 SetupSound
+BOOT:00ad SetupSound.initWaveRAM
+BOOT:00b3 DecodeLogoHalf
+BOOT:00b5 DecodeLogoHalf.decodeTileQuarter
+BOOT:00be DecodeLogoHalf.decodingLeftHalf
+BOOT:00cc DecodeLogoHalf.decodingRightHalf
+BOOT:00e1 DecodeLogoHalf.goToRightHalf
+BOOT:00e3 DecodeLogoHalf.decodingTopHalf
+BOOT:00ea WaitVBlank
+BOOT:00f0 WaitVBlank.wait
+BOOT:0104 HeaderLogo
+BOOT:0134 HeaderTitle
+BOOT:0150 SetOBJAndBGPals
+BOOT:0158 SetOBJAndBGPals.writeOBJPalData
+BOOT:0162 SetOBJAndBGPals.writeBGPalData
+BOOT:0168 CommitBGPalettes
+BOOT:017b DoLogoAnimation
+BOOT:018f DoLogoAnimation.writeNintendoLogoMap
+BOOT:019a DoLogoAnimation.dontWriteNintendoLogo
+BOOT:01b1 DoLogoAnimation.changePaletteRow
+BOOT:01b3 DoLogoAnimation.changePaletteBlock
+BOOT:01b5 DoLogoAnimation.changePaletteLoop
+BOOT:01cf DoLogoAnimation.dontWriteLogoAttrMap
+BOOT:01dd DoLogoAnimation.playSFX
+BOOT:01e4 DoLogoAnimation.dontAnimateLogo
+BOOT:01e4 DoLogoAnimation.dontPlaySFX
+BOOT:01f5 DoLogoAnimation.stepAnimation
+BOOT:01fa PerformFadeout
+BOOT:01fc PerformFadeout.loop
+BOOT:021f PerformFadeout.clearLogoArea
+BOOT:0222 PerformFadeout.clearLogoTiles
+BOOT:022b PerformFadeout.fadePalettes
+BOOT:0233 PerformFadeout.fadeColor
+BOOT:023b PerformFadeout.redCap
+BOOT:024f PerformFadeout.greenCap
+BOOT:0265 PerformFadeout.blueCap
+BOOT:0270 DecompressFirstNibble
+BOOT:0271 DecompressSecondNibble
+BOOT:0274 DecompressSecondNibble.decompressBit
+BOOT:0284 WriteLogoTilemap
+BOOT:028c WriteLogoTilemap.writeRow
+BOOT:028e WriteLogoTilemap.writeByte
+BOOT:0299 WriteLogoTilemap.done
+BOOT:029a SetupGameBoyLogo
+BOOT:02a9 SetupGameBoyLogo.copyLogoRow
+BOOT:02c8 SetupGameBoyLogo.copyRTile
+BOOT:02d6 SetupGameBoyLogo.writeAttrRow
+BOOT:02d8 SetupGameBoyLogo.writeAttrByte
+BOOT:02eb SetupGameBoyLogo.writeTilemapByte
+BOOT:02f3 SetupGameBoyLogo.notFirstRow
+BOOT:02fa SetupGameBoyLogo.notSecondRow
+BOOT:0306 SetupGameBoyLogo.initBGPalsLoop
+BOOT:0320 GameBoyLogoTiles
+BOOT:03e0 BootAnimationColors
+BOOT:03e0 GameBoyLogoTilesEnd
+BOOT:03ec BootAnimationColors.end
+00:8000 vBlankTile
+00:8010 vLogoTiles
+00:8190 vRTile
+00:9800 vTileMap
+00:98c2 vGameBoyLogoMap
+00:9904 vBigNintendoLogoMap
+00:99a7 vNintendoLogoMap
+01:8000 vTiles
+01:8080 vGameBoyLogoTiles
+01:8380 vNintendoLogoTiles
+01:83e0 vSecondRTile
+01:83f0 vNintendoLogoTilesEnd
+01:9800 vAttrMap
+01:98c2 vGameBoyLogoAttrs
+01:9904 vBigNintendoLogoAttrs
+01:99a7 vNintendoLogoAttrs
+02:d000 wWorkRAM
+02:d002 wPreventTerminationCounter
+02:d300 wZeroBuffer
+02:d800 wOBJPalBuffer
+02:d840 wBGPalBuffer
+02:d840 wOBJPalBufferEnd
+02:d880 wBGPalBufferEnd
+00:fffe hStackBottom
diff --git a/cpu_instrs/cpu_instrs.gb b/cpu_instrs/cpu_instrs.gb
new file mode 100644
index 0000000..7b06221
Binary files /dev/null and b/cpu_instrs/cpu_instrs.gb differ
diff --git a/cpu_instrs/individual/01-special.gb b/cpu_instrs/individual/01-special.gb
new file mode 100644
index 0000000..ad3e998
Binary files /dev/null and b/cpu_instrs/individual/01-special.gb differ
diff --git a/cpu_instrs/individual/02-interrupts.gb b/cpu_instrs/individual/02-interrupts.gb
new file mode 100644
index 0000000..2089594
Binary files /dev/null and b/cpu_instrs/individual/02-interrupts.gb differ
diff --git a/cpu_instrs/individual/03-op sp,hl.gb b/cpu_instrs/individual/03-op sp,hl.gb
new file mode 100644
index 0000000..50b3cc7
Binary files /dev/null and b/cpu_instrs/individual/03-op sp,hl.gb differ
diff --git a/cpu_instrs/individual/04-op r,imm.gb b/cpu_instrs/individual/04-op r,imm.gb
new file mode 100644
index 0000000..58ca7b8
Binary files /dev/null and b/cpu_instrs/individual/04-op r,imm.gb differ
diff --git a/cpu_instrs/individual/05-op rp.gb b/cpu_instrs/individual/05-op rp.gb
new file mode 100644
index 0000000..1c19d92
Binary files /dev/null and b/cpu_instrs/individual/05-op rp.gb differ
diff --git a/cpu_instrs/individual/06-ld r,r.gb b/cpu_instrs/individual/06-ld r,r.gb
new file mode 100644
index 0000000..d497bfd
Binary files /dev/null and b/cpu_instrs/individual/06-ld r,r.gb differ
diff --git a/cpu_instrs/individual/07-jr,jp,call,ret,rst.gb b/cpu_instrs/individual/07-jr,jp,call,ret,rst.gb
new file mode 100644
index 0000000..5c8d20b
Binary files /dev/null and b/cpu_instrs/individual/07-jr,jp,call,ret,rst.gb differ
diff --git a/cpu_instrs/individual/08-misc instrs.gb b/cpu_instrs/individual/08-misc instrs.gb
new file mode 100644
index 0000000..4da139b
Binary files /dev/null and b/cpu_instrs/individual/08-misc instrs.gb differ
diff --git a/cpu_instrs/individual/09-op r,r.gb b/cpu_instrs/individual/09-op r,r.gb
new file mode 100644
index 0000000..e30e6ec
Binary files /dev/null and b/cpu_instrs/individual/09-op r,r.gb differ
diff --git a/cpu_instrs/individual/10-bit ops.gb b/cpu_instrs/individual/10-bit ops.gb
new file mode 100644
index 0000000..8988458
Binary files /dev/null and b/cpu_instrs/individual/10-bit ops.gb differ
diff --git a/cpu_instrs/individual/11-op a,(hl).gb b/cpu_instrs/individual/11-op a,(hl).gb
new file mode 100644
index 0000000..0634b7f
Binary files /dev/null and b/cpu_instrs/individual/11-op a,(hl).gb differ
diff --git a/cpu_instrs/readme.txt b/cpu_instrs/readme.txt
new file mode 100644
index 0000000..6f94955
--- /dev/null
+++ b/cpu_instrs/readme.txt
@@ -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
diff --git a/cpu_instrs/source/01-special.s b/cpu_instrs/source/01-special.s
new file mode 100644
index 0000000..776d685
--- /dev/null
+++ b/cpu_instrs/source/01-special.s
@@ -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
diff --git a/cpu_instrs/source/02-interrupts.s b/cpu_instrs/source/02-interrupts.s
new file mode 100644
index 0000000..de18b34
--- /dev/null
+++ b/cpu_instrs/source/02-interrupts.s
@@ -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
+ 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
diff --git a/cpu_instrs/source/03-op sp,hl.s b/cpu_instrs/source/03-op sp,hl.s
new file mode 100644
index 0000000..9531d51
--- /dev/null
+++ b/cpu_instrs/source/03-op sp,hl.s
@@ -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 taken ; JP NZ,taken
+ .byte $C3,taken ; JP taken
+ .byte $CA,taken ; JP Z,taken
+ .byte $D2,taken ; JP NC,taken
+ .byte $DA,taken ; JP C,taken
+
+ .byte $C4,taken ; CALL NZ,taken
+ .byte $CC,taken ; CALL Z,taken
+ .byte $CD,taken ; CALL taken
+ .byte $D4,taken ; CALL NC,taken
+ .byte $DC,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"
diff --git a/cpu_instrs/source/08-misc instrs.s b/cpu_instrs/source/08-misc instrs.s
new file mode 100644
index 0000000..5c11c8e
--- /dev/null
+++ b/cpu_instrs/source/08-misc instrs.s
@@ -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,
diff --git a/cpu_instrs/source/09-op r,r.s b/cpu_instrs/source/09-op r,r.s
new file mode 100644
index 0000000..432c4e7
--- /dev/null
+++ b/cpu_instrs/source/09-op r,r.s
@@ -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 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 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 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
diff --git a/cpu_instrs/source/common/crc_fast.s b/cpu_instrs/source/common/crc_fast.s
new file mode 100644
index 0000000..d1088b0
--- /dev/null
+++ b/cpu_instrs/source/common/crc_fast.s
@@ -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
diff --git a/cpu_instrs/source/common/delay.s b/cpu_instrs/source/common/delay.s
new file mode 100644
index 0000000..65eb9c0
--- /dev/null
+++ b/cpu_instrs/source/common/delay.s
@@ -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
diff --git a/cpu_instrs/source/common/gb.inc b/cpu_instrs/source/common/gb.inc
new file mode 100644
index 0000000..31bbf14
--- /dev/null
+++ b/cpu_instrs/source/common/gb.inc
@@ -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
diff --git a/cpu_instrs/source/common/instr_test.s b/cpu_instrs/source/common/instr_test.s
new file mode 100644
index 0000000..5ed6e2c
--- /dev/null
+++ b/cpu_instrs/source/common/instr_test.s
@@ -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+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,-
+
+ 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
diff --git a/cpu_instrs/source/common/macros.inc b/cpu_instrs/source/common/macros.inc
new file mode 100644
index 0000000..c413bd5
--- /dev/null
+++ b/cpu_instrs/source/common/macros.inc
@@ -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
diff --git a/cpu_instrs/source/common/multi_custom.s b/cpu_instrs/source/common/multi_custom.s
new file mode 100644
index 0000000..4dbae9d
--- /dev/null
+++ b/cpu_instrs/source/common/multi_custom.s
@@ -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
diff --git a/cpu_instrs/source/common/numbers.s b/cpu_instrs/source/common/numbers.s
new file mode 100644
index 0000000..6d6faf8
--- /dev/null
+++ b/cpu_instrs/source/common/numbers.s
@@ -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
diff --git a/cpu_instrs/source/common/printing.s b/cpu_instrs/source/common/printing.s
new file mode 100644
index 0000000..ad9d811
--- /dev/null
+++ b/cpu_instrs/source/common/printing.s
@@ -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
diff --git a/cpu_instrs/source/common/runtime.s b/cpu_instrs/source/common/runtime.s
new file mode 100644
index 0000000..90cd24f
--- /dev/null
+++ b/cpu_instrs/source/common/runtime.s
@@ -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
diff --git a/cpu_instrs/source/common/testing.s b/cpu_instrs/source/common/testing.s
new file mode 100644
index 0000000..c102f78
--- /dev/null
+++ b/cpu_instrs/source/common/testing.s
@@ -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
diff --git a/cpu_instrs/source/linkfile b/cpu_instrs/source/linkfile
new file mode 100644
index 0000000..02a5a2e
--- /dev/null
+++ b/cpu_instrs/source/linkfile
@@ -0,0 +1,2 @@
+[objects]
+test.o
diff --git a/cpu_instrs/source/shell.inc b/cpu_instrs/source/shell.inc
new file mode 100644
index 0000000..277a9b7
--- /dev/null
+++ b/cpu_instrs/source/shell.inc
@@ -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
diff --git a/libpng16.dll b/libpng16.dll
new file mode 100644
index 0000000..36c2ce2
Binary files /dev/null and b/libpng16.dll differ
diff --git a/rgbasm.exe b/rgbasm.exe
new file mode 100644
index 0000000..1754a5e
Binary files /dev/null and b/rgbasm.exe differ
diff --git a/rgbfix.exe b/rgbfix.exe
new file mode 100644
index 0000000..de5f6c4
Binary files /dev/null and b/rgbfix.exe differ
diff --git a/rgbgfx.exe b/rgbgfx.exe
new file mode 100644
index 0000000..6277756
Binary files /dev/null and b/rgbgfx.exe differ
diff --git a/rgblink.exe b/rgblink.exe
new file mode 100644
index 0000000..1527eec
Binary files /dev/null and b/rgblink.exe differ
diff --git a/src/main.rs b/src/main.rs
index a7fd1df..1565d86 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,6 +9,8 @@ struct CPU {
pc: u16,
bus: MemoryBus,
sp: u16,
+ boot_rom: Vec,
+ game_rom: Vec,
}
const VRAM_BEGIN: usize = 0x8000;
const VRAM_END: usize = 0x9FFF;
@@ -117,14 +119,14 @@ impl MemoryBus {
self.write_byte(address.wrapping_add(1), high);
}
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
enum Target {
U8Register(TargetRegister),
U16Register(TargetU16Register),
Address(u16),
Immediate(u8)
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
enum Condition {
NZ, // Not Zero
Z, // Zero
@@ -133,7 +135,7 @@ enum Condition {
None
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
enum LoadTarget{
CopyR8R8(TargetRegister, TargetRegister),
CopyR8N8(TargetRegister, u8),
@@ -162,6 +164,7 @@ enum LoadTarget{
}
+#[derive(Debug)]
enum Instruction {
ADC(Target),
ADD(Target),
@@ -208,11 +211,28 @@ enum Instruction {
SWAP(Target),
XOR(Target),
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
enum TargetRegister { A, B, C, D, E, H, L, }
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
enum TargetU16Register {AF, BC, DE, HL, SP, PC}
impl CPU {
+
+ fn init(&mut self) {
+ let l = self.bus.memory.len();
+ println!("{l}");
+ println!("CPU init");
+ // println!("Boot ROM: {:02X?}", self.boot_rom);
+ for (address, byte) in self.boot_rom.iter().enumerate() {
+ self.bus.write_byte(address as u16, *byte);
+ }
+ // println!("Game ROM: {:02X?}", self.game_rom);
+ for (address, byte) in self.game_rom.iter().enumerate() {
+ if address < 0x100 { continue; }
+ if address >= 0x4000 { break; }
+ self.bus.write_byte(address as u16, *byte);
+ }
+
+ }
fn check_condition(&self, condition: Condition) -> bool {
match condition {
Condition::NZ => !self.registers.f.zero,
@@ -1264,11 +1284,23 @@ impl CPU {
fn main() {
+ let boot_rom = std::fs::read("boot/dmg.bin").unwrap();
+ let game_rom = std::fs::read("cpu_instrs/cpu_instrs.gb").unwrap();
- let gameboy = CPU{
+ let mut gameboy = CPU{
registers:Registers{a:0,b:0,c:0,d:0,e:0,f:FlagsRegister::from(0),h:0,l:0},
pc:0,
bus:MemoryBus{ memory: [0xFFu8; 0xFFFF], gpu:GPU{ vram: Vec::with_capacity(VRAM_END-VRAM_BEGIN), tile_set: [[[TilePixelValue::Zero; 8]; 8]; 384] }},
- sp: 0
+ sp: 0,
+ boot_rom,
+ game_rom,
};
+ gameboy.init();
+ let sp = gameboy.sp;
+ println!("{sp:?}");
+ let f = gameboy.next_instruction();
+ println!("{f:?}");
+ gameboy.execute(f);
+ let sp = gameboy.sp;
+ println!("{sp:?}");
}
diff --git a/zlib1.dll b/zlib1.dll
new file mode 100644
index 0000000..49cb57d
Binary files /dev/null and b/zlib1.dll differ