├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── img ├── failures │ ├── 10-obj-limit.png │ ├── 8x16-obj-tile-index-bit-0.png │ ├── bg-horizontal-flip.png │ ├── bg-map-vram-bank.png │ ├── bg-map.png │ ├── bg-to-oam-priority.png │ ├── bg-vertical-flip.png │ ├── master-priority-dmg-green.png │ ├── master-priority-dmg-white.png │ ├── master-priority.png │ ├── obj-enable.png │ ├── obj-horizontal-flip.png │ ├── obj-priority-mode.png │ ├── obj-size.png │ ├── obj-to-bg-priority.png │ ├── obj-vertical-flip.png │ ├── obj-vram-bank.png │ ├── tile-sel.png │ ├── win-enable.png │ ├── win-line-counter.png │ └── win-map.png ├── footer.png ├── photo.jpg └── reference.png ├── inc ├── background.asm ├── oam.asm ├── palettes.asm ├── tiles.asm └── window.asm └── src └── cgb-acid2.asm /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.2bpp -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "mgblib"] 2 | path = mgblib 3 | url = https://github.com/mattcurrie/mgblib 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Matt Currie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRCDIR = src 2 | OBJDIR = build 3 | IMAGE_DEPS = img/footer.2bpp 4 | 5 | SOURCES := $(wildcard $(SRCDIR)/*.asm) 6 | OBJECTS := $(SOURCES:$(SRCDIR)/%.asm=$(OBJDIR)/%.o) 7 | ROMS := $(SOURCES:$(SRCDIR)/%.asm=$(OBJDIR)/%.gbc) 8 | 9 | all: $(OBJDIR) $(ROMS) 10 | 11 | %.2bpp: %.png 12 | rgbgfx -o $@ $< 13 | 14 | $(OBJDIR): 15 | @echo "Creating $(directory)..." 16 | mkdir -p $@ 17 | 18 | $(ROMS): $(OBJDIR)/%.gbc : $(OBJDIR)/%.o 19 | rgblink -n $(basename $@).sym -m $(basename $@).map -o $@ $< 20 | rgbfix -C -t "CGB-ACID2" -v -p 255 $@ 21 | 22 | -include $(OBJECTS:.o=.d) 23 | 24 | $(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.asm $(IMAGE_DEPS) 25 | rgbasm -i mgblib/ -M $(OBJDIR)/$*.d -o $@ $< 26 | 27 | .PHONY: clean 28 | clean: 29 | rm -rf $(OBJDIR) 30 | rm img/*.2bpp 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cgb-acid2 2 | cgb-acid2 is a test for developers of Game Boy Color emulators to verify their 3 | emulation of the Game Boy Color's Pixel Processing Unit (PPU). 4 | 5 | [Download the ROM](https://github.com/mattcurrie/cgb-acid2/releases/download/v1.1/cgb-acid2.gbc), 6 | or build using [RGBDS](https://github.com/rednex/rgbds): 7 | 8 | ``` 9 | git clone --recurse-submodules https://github.com/mattcurrie/cgb-acid2 10 | cd cgb-acid2 && make 11 | ``` 12 | 13 | For testing the Game Boy (DMG) you can try [dmg-acid2](https://github.com/mattcurrie/dmg-acid2). 14 | 15 | ## Reference Image 16 | An accurate emulator should generate output identical to the image below: 17 | 18 | ![reference image](img/reference.png) 19 | 20 | If you want to automate testing using the reference image, you should use this 21 | formula to convert each 5-bit CGB palette component to 8-bit: 22 | `(r << 3) | (r >> 2)` 23 | 24 | [Reference photo from a real device](https://github.com/mattcurrie/cgb-acid2/raw/master/img/photo.jpg) 25 | 26 | ## Emulator Requirements 27 | A simple line based renderer is sufficient to generate the correct output. This 28 | is NOT a [PPU timing torture test requiring T-cycle accuracy](https://github.com/mattcurrie/mealybug-tearoom-tests), 29 | and does NOT perform register writes during the PPU's mode 3. 30 | 31 | The test uses LY=LYC coincidence interrupts to perform register writes on 32 | specific rows of the screen during mode 2 (OAM scan). 33 | 34 | Double speed mode and WRAM banking emulation are not required. 35 | 36 | ## Guide 37 | 38 | ### Hello World! 39 | The "Hello World" text is constructed from 10 objects, and the exclaimation 40 | mark is part of the background. There is also an additional solid white object 41 | where the exclaimation mark is. Due to the 10 object per line limit, the solid 42 | white object should not be drawn, allowing the background to show through. 43 | 44 | ### Eyes 45 | The eyes consist of four background/window tiles using the same tile data that 46 | is flipped vertically and/or horizontally. The top left corner of the eye 47 | contains the unflipped tile. 48 | 49 | The left eye is drawn using the background, and the right eye is drawn using 50 | the window (and also the right edge of the head beside the right eye). At the 51 | bottom of the eye, the WX register is set to an off-screen value, so the window 52 | is hidden until the WX register is set again for drawing the right side of the 53 | chin. 54 | 55 | The background/window tiles for the top left corner of both eyes use red for 56 | color 0. A green object is positioned overlapping it with OBJ-to-BG Priority 57 | (bit 7) set in the OAM flags, so the green object only shows through color 0 of 58 | the background/window tile and replaces the red color. 59 | 60 | The background/window tiles for the top right corner of both eye use red for 61 | color 0 with BG-to-OAM Priority (bit 7) set in the background map attributes. A 62 | green object is positioned overlapping it, so the green object only shows 63 | through color 0 of the background tile and replaces the red color. 64 | 65 | ### Nose 66 | The nose consists of four objects using the same tile data that is flipped 67 | vertically and/or horizontally. The top left corner of the nose contains the 68 | unflipped tile. The tile data comes from VRAM bank 1. 69 | 70 | The background tiles behind the nose have BG-to-OAM Priority (bit 7) set in the 71 | background map attributes, however for this section of the screen the Master 72 | Priority (bit 0) of LCDC has been reset, so the objects are always on top 73 | regardless of the background map attribute setting. 74 | 75 | ### Mole 76 | The mole is not visible in the reference image, but can be seen in the failure 77 | case image for Object Priority Mode (DMG/CGB). 78 | 79 | This part of the test consists of two overlapping objects: a blank yellow 80 | square, and a black dot/"mole". The blank yellow square object OAM entry is 81 | before the mole, so effectively covers the mole even though the mole object has 82 | a lower X coordinate. 83 | 84 | ### Mouth 85 | The mouth consists of eight 8x16 objects. The left and right edges of the mouth 86 | contain unflipped tile data, and other objects use vertically flipped tile 87 | data. 88 | 89 | For the left side of the mouth, the objects specify tile index 6, and the right 90 | side of the mouth specify tile index 7. Because bit 0 of the tile index is 91 | ignored for 8x16 objects, the whole mouth effectively uses tile index 6. 92 | 93 | ### Chin 94 | The right side of the chin is drawn using the window. After the right eye was 95 | drawn, the window was hidden by setting WX to an off-screen value. For the 96 | right side of the chin, the WX value is restored to an on-screen value. After 97 | the chin has been drawn, the window is disabled using bit 5 of the LCDC 98 | register so the window does not cover the footer text. 99 | 100 | For the right side of the chin, the window has been updated to use the tile map 101 | from the VRAM beginning at $9800. Because 16 rows of window have already been 102 | drawn for the eye, the right side of the chin is rendered starting from address 103 | $9840. 104 | 105 | ### Footer Text 106 | For the footer text, the background is set to use the $9c00-9fff region for 107 | the map data, and tile data is set to come from the $8800-97ff region. 108 | 109 | ## Failure Examples 110 | See the table below for some examples of incorrect behaviour and the 111 | corresponding attribute/flag. This is not intended to be an exhaustive list of 112 | all possible failures. 113 | 114 | | Failure Example | Functionality Tested | 115 | | --------------- | ---------------------| 116 | | ![failure image](img/failures/bg-map-vram-bank.png)| Background Tile VRAM Bank (bit 3) | 117 | | ![failure image](img/failures/bg-horizontal-flip.png) | Background Tile Horizontal Flip (bit 5) | 118 | | ![failure image](img/failures/bg-vertical-flip.png) | Background Tile Vertical Flip (bit 6) | 119 | | ![failure image](img/failures/bg-to-oam-priority.png) | Background to OAM Priority (bit 7) | 120 | | ![failure image](img/failures/obj-vram-bank.png) | Object Tile Data VRAM Bank (bit 3) | 121 | | ![failure image](img/failures/obj-horizontal-flip.png) | Object Horizontal Flip (bit 5) | 122 | | ![failure image](img/failures/obj-vertical-flip.png) | Object Vertical Flip (bit 6) | 123 | | ![failure image](img/failures/obj-to-bg-priority.png) | Object to Background Priority (bit 7) | 124 | | ![failure image](img/failures/master-priority.png) ![failure image](img/failures/master-priority-dmg-white.png) ![failure image](img/failures/master-priority-dmg-green.png) | Master Priority (bit 0) | 125 | | ![failure image](img/failures/obj-enable.png) | Object Enable (bit 1) | 126 | | ![failure image](img/failures/obj-size.png) | Object Size (bit 2) | 127 | | ![failure image](img/failures/bg-map.png) | Background Tile Map (bit 3) | 128 | | ![failure image](img/failures/tile-sel.png) | Background/Window Tile Data (bit 4) | 129 | | ![failure image](img/failures/win-enable.png) | Window Enable (bit 5) | 130 | | ![failure image](img/failures/win-map.png) | Window Tile Map (bit 6) | 131 | | ![failure image](img/failures/win-line-counter.png) | Window internal line counter | 132 | | ![failure image](img/failures/obj-priority-mode.png) | Object Priority Mode (DMG/CGB) $FF6C (bit 0) - should prioritise by OAM position | 133 | | ![failure image](img/failures/10-obj-limit.png) | 10 object per line limit | 134 | | ![failure image](img/failures/8x16-obj-tile-index-bit-0.png) | Bit 0 of tile index for 8x16 objects should be ignored | 135 | 136 | ## Credits 137 | Håkon Wium Lie and Ian Hickson for creation of the original 138 | [Acid2](http://www.acidtests.org/) web standards compliance test. 139 | -------------------------------------------------------------------------------- /img/failures/10-obj-limit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/10-obj-limit.png -------------------------------------------------------------------------------- /img/failures/8x16-obj-tile-index-bit-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/8x16-obj-tile-index-bit-0.png -------------------------------------------------------------------------------- /img/failures/bg-horizontal-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/bg-horizontal-flip.png -------------------------------------------------------------------------------- /img/failures/bg-map-vram-bank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/bg-map-vram-bank.png -------------------------------------------------------------------------------- /img/failures/bg-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/bg-map.png -------------------------------------------------------------------------------- /img/failures/bg-to-oam-priority.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/bg-to-oam-priority.png -------------------------------------------------------------------------------- /img/failures/bg-vertical-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/bg-vertical-flip.png -------------------------------------------------------------------------------- /img/failures/master-priority-dmg-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/master-priority-dmg-green.png -------------------------------------------------------------------------------- /img/failures/master-priority-dmg-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/master-priority-dmg-white.png -------------------------------------------------------------------------------- /img/failures/master-priority.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/master-priority.png -------------------------------------------------------------------------------- /img/failures/obj-enable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/obj-enable.png -------------------------------------------------------------------------------- /img/failures/obj-horizontal-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/obj-horizontal-flip.png -------------------------------------------------------------------------------- /img/failures/obj-priority-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/obj-priority-mode.png -------------------------------------------------------------------------------- /img/failures/obj-size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/obj-size.png -------------------------------------------------------------------------------- /img/failures/obj-to-bg-priority.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/obj-to-bg-priority.png -------------------------------------------------------------------------------- /img/failures/obj-vertical-flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/obj-vertical-flip.png -------------------------------------------------------------------------------- /img/failures/obj-vram-bank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/obj-vram-bank.png -------------------------------------------------------------------------------- /img/failures/tile-sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/tile-sel.png -------------------------------------------------------------------------------- /img/failures/win-enable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/win-enable.png -------------------------------------------------------------------------------- /img/failures/win-line-counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/win-line-counter.png -------------------------------------------------------------------------------- /img/failures/win-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/failures/win-map.png -------------------------------------------------------------------------------- /img/footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/footer.png -------------------------------------------------------------------------------- /img/photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/photo.jpg -------------------------------------------------------------------------------- /img/reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattcurrie/cgb-acid2/04c6ca40cf75b6a93513fe596de4ab797efaff97/img/reference.png -------------------------------------------------------------------------------- /inc/background.asm: -------------------------------------------------------------------------------- 1 | BackgroundMap:: 2 | db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "!", 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 3 | db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 4 | db 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 5 | db 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 6 | db 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 7 | db 0, 0, 0, 0, 1, 2, 2, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 8 | db 0, 0, 0, 0, 1, 2, 2, 3, 3, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 9 | db 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 10 | db 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 11 | db 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 12 | db 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 13 | db 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 14 | db 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 15 | db 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 16 | db 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 17 | db 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 18 | .end: 19 | 20 | BackgroundMapAttributes:: 21 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $04, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 22 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 23 | db $00, $00, $00, $00, $00, $00, $00, $00, $02, $02, $02, $02, $00, $00, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 24 | db $00, $00, $00, $00, $00, $00, $02, $02, $02, $02, $02, $02, $02, $02, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 25 | db $00, $00, $00, $00, $00, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 26 | db $00, $00, $00, $00, $02, $02, $02, $0b, $ab, $02, $02, $00, $00, $00, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 27 | db $00, $00, $00, $00, $02, $02, $02, $4a, $6a, $02, $02, $00, $00, $00, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 28 | db $00, $00, $00, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 29 | db $00, $00, $00, $02, $02, $02, $02, $02, $02, $82, $82, $02, $02, $02, $02, $02, $02, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 30 | db $00, $00, $00, $02, $02, $02, $02, $02, $02, $82, $82, $02, $02, $02, $02, $02, $02, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 31 | db $00, $00, $00, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 32 | db $00, $00, $00, $00, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 33 | db $00, $00, $00, $00, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 34 | db $00, $00, $00, $00, $00, $02, $02, $02, $02, $02, $02, $02, $02, $02, $02, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 35 | db $00, $00, $00, $00, $00, $00, $02, $02, $02, $02, $02, $00, $00, $00, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 36 | db $00, $00, $00, $00, $00, $00, $00, $00, $02, $02, $02, $00, $00, $00, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 37 | .end: 38 | -------------------------------------------------------------------------------- /inc/oam.asm: -------------------------------------------------------------------------------- 1 | 2 | 3 | OAMData:: 4 | ; nose - all tile data from vram bank 1 5 | db $50, $50, $4, $08 6 | db $50, $58, $4, $28 7 | db $58, $50, $4, $48 8 | db $58, $58, $4, $68 9 | 10 | ; left eye - overlapping background color 0 only 11 | db $38, $40, $1, $82 ; uses green palette with priority so should show through color 0 bg, replacing the red top left corner of eye 12 | db $38, $48, $1, $02 ; green square. should show through color 0 because tile has set background to always have priority set 13 | 14 | ; right eye - overlapping window color 0 only 15 | db $38, $60, $1, $82 ; uses green palette with priority so should show through color 0 bg, replacing the red top left corner of eye 16 | db $38, $68, $1, $02 ; green square. should show through color 0 because tile has set background to always have priority set 17 | 18 | db $10, $28, "H", 3 19 | db $10, $30, "e", 3 20 | db $10, $38, "l", 3 21 | db $10, $40, "l", 3 22 | db $10, $48, "o", 3 23 | 24 | db $10, $58, "W", 3 25 | db $10, $60, "o", 3 26 | db $10, $68, "r", 3 27 | db $10, $70, "l", 3 28 | db $10, $78, "d", 3 29 | db $10, $80, 1, 4 ; this solid white box shouldn't display - 10 sprite limit per line 30 | 31 | ; mouth 32 | db $68, $38, 6, $00 ; sprite size is 8x16 when these sprites are rendered 33 | db $68, $40, 6, $40 ; y-flipped 8x16 sprite 34 | db $68, $48, 6, $40 35 | db $68, $50, 6, $40 36 | db $68, $58, 7, $40 ; specify tile 7, but bit 0 of tile index is ignored in 8x16 tile mode 37 | db $68, $60, 7, $40 38 | db $68, $68, 7, $40 39 | db $68, $70, 7, $00 40 | 41 | 42 | db $52, $3d, 10, $00 ; yellow square - higher x-coordinate, but lower index in OAM 43 | ; so appears on top of the mole 44 | db $52, $3b, 9, $00 ; mole 45 | 46 | 47 | db $38, $3a, 5, $0d ; left eyelash top 48 | db $40, $3a, 6, $0d ; left eyelash bottom 49 | 50 | db $38, $6e, 5, $2d ; right eyelash top 51 | db $40, $6e, 6, $2d ; right eyelash bottom 52 | 53 | db $78, $54, 1, $01 ; tongue 54 | .end: 55 | -------------------------------------------------------------------------------- /inc/palettes.asm: -------------------------------------------------------------------------------- 1 | 2 | BackgroundPalette:: 3 | ; palette 0 4 | rgb 31, 31, 31 5 | rgb 21, 21, 21 6 | rgb 11, 11, 11 7 | rgb 0, 0, 0 8 | 9 | ; palette 1 10 | rgb 0, 0, 31 ; 0 = blue 11 | rgb 0, 31, 00 ; 1 = green 12 | rgb 31, 0, 0 ; 2 = red 13 | rgb 0, 0, 0 ; 3 = black 14 | 15 | ; palette 2 16 | rgb 0, 19, 00 ; 0 = mid-green 17 | rgb 31, 31, 00 ; 1 = yellow 18 | rgb 31, 31, 31 ; 2 = white 19 | rgb 0, 0, 0 ; 3 = black 20 | 21 | ; palette 3 22 | rgb 31, 0, 00 ; 0 = red 23 | rgb 31, 31, 00 ; 1 = yellow 24 | rgb 31, 31, 31 ; 2 = white 25 | rgb 0, 0, 0 ; 3 = black 26 | 27 | ; palette 4 - "!" in "hello world!" text 28 | rgb 31, 31, 31 ; 0 = white 29 | rgb 0, 0, 31 ; 1 = blue 30 | rgb 31, 0, 31 ; 2 = purple 31 | rgb 13, 23, 31 ; 3 = light blue 32 | .end: 33 | 34 | ObjectPalette:: 35 | ; palette 0 36 | rgb 31, 0, 31 ; 0 = purple (unused) 37 | rgb 31, 31, 0 ; 1 = yellow 38 | rgb 31, 31, 31 ; 2 = white 39 | rgb 0, 0, 0 ; 3 = black 40 | 41 | ; palette 1 42 | rgb 31, 31, 31 ; 0 = white (unused) 43 | rgb 31, 31, 31 ; 1 = white 44 | rgb 31, 0, 0 ; 2 = red 45 | rgb 31, 0, 0 ; 3 = red 46 | 47 | ; palette 2 48 | rgb 31, 31, 31 ; 0 = white (unused) 49 | rgb 31, 31, 31 ; 1 = white 50 | rgb 31, 0, 0 ; 2 = white 51 | rgb 0, 19, 0 ; 3 = red 52 | 53 | ; palette 3 - "hello world!" text 54 | rgb 31, 0, 31 ; 0 = purple (unused) 55 | rgb 0, 0, 31 ; 1 = blue 56 | rgb 31, 0, 31 ; 2 = purple 57 | rgb 13, 23, 31 ; 3 = light blue 58 | 59 | ; palette 4 - cover for the "!" in "hello world!" text - 60 | ; if the sprite limit doesn't kick in this will overlap the "!" from the background 61 | rgb 31, 31, 31 ; 0 = white 62 | rgb 31, 31, 31 ; 1 = white 63 | rgb 31, 31, 31 ; 2 = white 64 | rgb 31, 31, 31 ; 3 = white 65 | 66 | ; palette 5 - eye lash 67 | rgb 31, 0, 31 ; 0 = purple (unused) 68 | rgb 21, 21, 0 ; 1 = mid yellow 69 | rgb 14, 14, 0 ; 2 = dark yellow 70 | rgb 0, 0, 0 ; 3 = black 71 | .end: -------------------------------------------------------------------------------- /inc/tiles.asm: -------------------------------------------------------------------------------- 1 | TileData:: 2 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 3 | db $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff 4 | db $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00 5 | 6 | ; 3: diagonal line 7 | dw `31111111 8 | dw `13111111 9 | dw `11311111 10 | dw `11131111 11 | dw `11113111 12 | dw `11111311 13 | dw `11111131 14 | dw `11111113 15 | 16 | ; 4: diagonal line 17 | dw `31111111 18 | dw `13111111 19 | dw `11311111 20 | dw `11131111 21 | dw `11113111 22 | dw `11111311 23 | dw `11111131 24 | dw `11111113 25 | 26 | ; 5: blank 27 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 28 | 29 | ; 6 mouth 30 | db $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff 31 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 32 | 33 | ; 8 (should not be used for mouth on 8x16 object with tile index 7) 34 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 35 | 36 | ; 9 mole 37 | dw `00000000 38 | dw `00000000 39 | dw `00003300 40 | dw `00033330 41 | dw `00033330 42 | dw `00003300 43 | dw `00000000 44 | dw `00000000 45 | 46 | ; 10 mole-cover 47 | dw `11111111 48 | dw `11111111 49 | dw `11111111 50 | dw `11111111 51 | dw `11111111 52 | dw `11111111 53 | dw `11111111 54 | dw `11111111 55 | .end: 56 | 57 | TileDataBank1:: 58 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 59 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 60 | db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 61 | 62 | ; 3: one corner of eye (slash will be displayed if not using correct vram bank) 63 | dw `11111133 64 | dw `11113333 65 | dw `11133322 66 | dw `11332200 67 | dw `13322000 68 | dw `13320000 69 | dw `33200000 70 | dw `33200000 71 | 72 | ; 4: one corner of the nose 73 | dw `00000003 74 | dw `00000033 75 | dw `00000333 76 | dw `00003333 77 | dw `00033333 78 | dw `00333333 79 | dw `03333333 80 | dw `33333333 81 | 82 | ; 5: eye lash top 83 | dw `00001100 84 | dw `00122100 85 | dw `01221000 86 | dw `02210000 87 | dw `12210000 88 | dw `22100000 89 | dw `22100000 90 | dw `22100000 91 | 92 | ; 6: eye lash bottom 93 | dw `12200000 94 | dw `02200000 95 | dw `01210000 96 | dw `00120000 97 | dw `00011000 98 | dw `00000000 99 | dw `00000000 100 | dw `00000000 101 | .end: -------------------------------------------------------------------------------- /inc/window.asm: -------------------------------------------------------------------------------- 1 | WindowMap:: 2 | db 3, 3, 2, 2, 1, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 3 | db 3, 3, 2, 2, 1, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 4 | .end: 5 | 6 | WindowMap9840:: 7 | db 2, 1, 1, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 8 | db 1, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 9 | .end: 10 | 11 | WindowMapAttributes:: 12 | db $0b, $ab, $02, $02, $02, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 13 | db $4a, $6a, $02, $02, $02, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 14 | .end: 15 | 16 | WindowMapAttributes9840:: 17 | db $02, $02, $02, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 18 | db $02, $00, $00, $00, $00, $00, $00, $00, $00, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09, $09 19 | .end: 20 | -------------------------------------------------------------------------------- /src/cgb-acid2.asm: -------------------------------------------------------------------------------- 1 | SECTION "mgblib", ROMX 2 | INCLUDE "mgblib/src/hardware.inc" 3 | INCLUDE "mgblib/src/macros.asm" 4 | enable_cgb_mode 5 | INCLUDE "mgblib/src/old_skool_outline_thick.asm" 6 | INCLUDE "mgblib/src/display.asm" 7 | 8 | 9 | SECTION "stat_int", ROM0[$48] 10 | jp hl 11 | 12 | 13 | SECTION "boot", ROM0[$100] 14 | nop 15 | jp Main 16 | 17 | 18 | SECTION "main", ROM0[$150] 19 | Main:: 20 | di 21 | ld sp, $cfff 22 | 23 | call ResetDisplay 24 | call LoadFont8000 25 | 26 | ld hl, BackgroundPalette 27 | xor a 28 | ld b, BackgroundPalette.end - BackgroundPalette 29 | call LoadBackgroundPalette 30 | 31 | ld hl, ObjectPalette 32 | xor a 33 | ld b, ObjectPalette.end - ObjectPalette 34 | call LoadObjectPalette 35 | 36 | ld hl, OAMData 37 | ld de, _OAMRAM 38 | ld bc, OAMData.end - OAMData 39 | call MemCopy 40 | 41 | ; select vram bank 1 42 | ld a, 1 43 | ldh [rVBK], a 44 | 45 | ld hl, BackgroundMapAttributes 46 | ld de, $9880 47 | ld bc, BackgroundMapAttributes.end - BackgroundMapAttributes 48 | call MemCopy 49 | 50 | ld hl, WindowMapAttributes 51 | ld de, $9c00 52 | ld bc, WindowMapAttributes.end - WindowMapAttributes 53 | call MemCopy 54 | 55 | ld hl, WindowMapAttributes9840 56 | ld de, $9840 57 | ld bc, WindowMapAttributes9840.end - WindowMapAttributes9840 58 | call MemCopy 59 | 60 | ld hl, TileDataBank1 61 | ld de, $8000 62 | ld bc, TileDataBank1.end - TileDataBank1 63 | call MemCopy 64 | 65 | ; select vram bank 0 66 | xor a 67 | ldh [rVBK], a 68 | 69 | ; set the footer tile map 70 | ld hl, $9e80 71 | xor a 72 | ld c, 20 73 | .loop: 74 | ld [hl+], a 75 | inc a 76 | dec c 77 | jr nz, .loop 78 | ld l, $a0 79 | 80 | ld c, 20 81 | .loop2: 82 | ld [hl+], a 83 | inc a 84 | dec c 85 | jr nz, .loop2 86 | 87 | ld hl, BackgroundMap 88 | ld de, $9880 89 | ld bc, BackgroundMap.end - BackgroundMap 90 | call MemCopy 91 | 92 | ld hl, WindowMap 93 | ld de, $9c00 94 | ld bc, WindowMap.end - WindowMap 95 | call MemCopy 96 | 97 | ld hl, WindowMap9840 98 | ld de, $9840 99 | ld bc, WindowMap9840.end - WindowMap9840 100 | call MemCopy 101 | 102 | ld hl, TileData 103 | ld de, $8000 104 | ld bc, TileData.end - TileData 105 | call MemCopy 106 | 107 | ld hl, FooterTiles 108 | ld de, $9000 109 | ld bc, FooterTiles.end - FooterTiles 110 | call MemCopy 111 | 112 | 113 | ; enable interrupt for ly=lyc 114 | ld a, $40 115 | ldh [rSTAT], a 116 | ld a, $57 117 | ldh [rLYC], a 118 | ld a, 2 119 | ldh [rIE], a 120 | 121 | ld a, $20 122 | ldh [rSCY], a 123 | ld a, $28 124 | ldh [rWY], a 125 | ld a, $58 + 7 126 | ldh [rWX], a 127 | 128 | win_map_9c00 129 | enable_sprites 130 | bg_tile_data_8000 131 | lcd_on 132 | 133 | xor a 134 | ldh [rIF], a 135 | 136 | ; schedule first job 137 | ld a, $10 138 | ldh [rLYC], a 139 | ld hl, LY_10 140 | 141 | ; initialise the frame counter 142 | ; a source code breakpoint will be triggered after 10 frames 143 | ld b, 10 144 | 145 | ei 146 | 147 | .forever 148 | halt 149 | jr .forever 150 | 151 | LY_10: 152 | ld hl, rLCDC 153 | set 5, [hl] ; enable window 154 | 155 | ld a, $38 156 | ldh [rLYC], a 157 | ld hl, LY_38 158 | reti 159 | 160 | LY_38: 161 | ; disable window by setting WX off-screen 162 | ld a, 240 163 | ld [rWX], a 164 | 165 | ld hl, rLCDC 166 | res 0, [hl] ; objects always on top - displays the nose 167 | 168 | ld a, $58 169 | ldh [rLYC], a 170 | ld hl, LY_58 171 | reti 172 | 173 | LY_58: 174 | ld hl, rLCDC 175 | set 2, [hl] ; object size 8x16 176 | set 0, [hl] ; allow bg map attributes/oam to specify object priority 177 | 178 | ld a, $68 179 | ldh [rLYC], a 180 | ld hl, LY_68 181 | reti 182 | 183 | LY_68: 184 | ld hl, rLCDC 185 | res 2, [hl] ; object size 8x8 186 | res 1, [hl] ; objects disabled - hides the tongue 187 | 188 | ld a, $70 189 | ldh [rLYC], a 190 | ld hl, LY_70 191 | reti 192 | 193 | 194 | LY_70: 195 | ; enable window by positioning WX on-screen 196 | ld a, $58 + 7 197 | ld [rWX], a 198 | 199 | ld hl, rLCDC 200 | res 6, [hl] ; window map $9800 201 | 202 | ld a, $80 203 | ldh [rLYC], a 204 | ld hl, LY_80 205 | reti 206 | 207 | 208 | LY_80: 209 | ld hl, rLCDC 210 | set 3, [hl] ; bg map $9c00 211 | res 4, [hl] ; bg tiles at $8800-97ff 212 | 213 | ld a, $81 214 | ldh [rLYC], a 215 | ld hl, LY_81 216 | reti 217 | 218 | 219 | LY_81: 220 | ld hl, rLCDC 221 | res 5, [hl] ; disable window 222 | set 6, [hl] ; window map $9c00 223 | 224 | ld a, $8f 225 | ldh [rLYC], a 226 | ld hl, LY_8F 227 | reti 228 | 229 | 230 | LY_8F: 231 | ; bg uses $9800 tile map and $8000 tile data 232 | ld hl, rLCDC 233 | res 3, [hl] 234 | set 4, [hl] 235 | 236 | ld a, $90 237 | ldh [rLYC], a 238 | ld hl, LY_90 239 | reti 240 | 241 | LY_90: 242 | ld hl, rLCDC 243 | set 1, [hl] ; enable objects 244 | 245 | ; decrease the frame counter 246 | dec b 247 | jr nz, .skip 248 | 249 | ; source code breakpoint - good time to take a 250 | ; screenshot to compare to reference image 251 | ld b, b 252 | 253 | .skip: 254 | ld a, $10 255 | ldh [rLYC], a 256 | ld hl, LY_10 257 | reti 258 | 259 | INCLUDE "inc/background.asm" 260 | INCLUDE "inc/window.asm" 261 | INCLUDE "inc/tiles.asm" 262 | INCLUDE "inc/oam.asm" 263 | INCLUDE "inc/palettes.asm" 264 | FooterTiles:: 265 | INCBIN "img/footer.2bpp" 266 | .end: --------------------------------------------------------------------------------