diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7702300 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +*.2bpp \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2d24242 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "mgblib"] + path = mgblib + url = https://github.com/mattcurrie/mgblib diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..206c3e2 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +SRCDIR = src +OBJDIR = build +IMAGE_DEPS = img/footer.2bpp + +SOURCES := $(wildcard $(SRCDIR)/*.asm) +OBJECTS := $(SOURCES:$(SRCDIR)/%.asm=$(OBJDIR)/%.o) +ROMS := $(SOURCES:$(SRCDIR)/%.asm=$(OBJDIR)/%.gb) + +all: $(OBJDIR) $(ROMS) + +%.2bpp: %.png + rgbgfx -o $@ $< + +$(OBJDIR): + @echo "Creating $(directory)..." + mkdir -p $@ + +$(ROMS): $(OBJDIR)/%.gb : $(OBJDIR)/%.o + rgblink -n $(basename $@).sym -m $(basename $@).map -o $@ $< + rgbfix -t "DMG-ACID2" -v -p 255 $@ + +-include $(OBJECTS:.o=.d) + +$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.asm $(IMAGE_DEPS) + rgbasm -i mgblib/ -M $(OBJDIR)/$*.d -o $@ $< + +.PHONY: clean +clean: + rm -rf $(OBJDIR) + rm img/*.2bpp diff --git a/README.md b/README.md index 12be4da..f23bd8a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,148 @@ # dmg-acid2 - 😀 The Acid2 test, now for Game Boy! 😀 +dmg-acid2 is a test for developers of Game Boy (DMG) emulators to verify their +emulation of the Game Boy's Pixel Processing Unit (PPU). + +[Download the ROM](https://github.com/mattcurrie/dmg-acid2/releases/download/v1.0/dmg-acid2.gb), +or build using [RGBDS](https://github.com/rednex/rgbds): + +``` +git clone --recurse-submodules https://github.com/mattcurrie/dmg-acid2 +cd dmg-acid2 && make +``` + +For testing the Game Boy Color you can try [cgb-acid2](https://github.com/mattcurrie/cgb-acid2). + +## Reference Image +An accurate DMG emulator should generate output identical to the image below: + +![reference image](img/reference-dmg.png) + +An accurate CGB emulator running in DMG mode should generate output identical +to the image below: + +![reference image](img/reference-cgb.png) + +A DMG emulator should use these 8-bit values in greyscale images or in RGB +components to ensure the images can be compared correctly: +`$00`, `$55`, `$AA`, `$FF`. + +When emulating a CGB running in DMG mode, you should use this formula to +convert each 5-bit CGB palette component to 8-bit: +`(r << 3) | (r >> 2)` + +[Reference photo from DMG](https://github.com/mattcurrie/dmg-acid2/raw/master/img/photo-dmg.jpg) +[Reference photo from CGB](https://github.com/mattcurrie/dmg-acid2/raw/master/img/photo-cgb.jpg) + +## Emulator Requirements +A simple line based renderer is sufficient to generate the correct output. This +is NOT a [PPU timing torture test requiring T-cycle accuracy](https://github.com/mattcurrie/mealybug-tearoom-tests), +and does NOT perform register writes during the PPU's mode 3. + +The test uses LY=LYC coincidence interrupts to perform register writes on +specific rows of the screen during mode 2 (OAM scan). + +## Guide + +### Hello World! +The "Hello World" text is constructed from 10 objects, and the exclaimation +mark is part of the background. There is also an additional solid white object +where the exclaimation mark is. Due to the 10 object per line limit, the solid +white object should not be drawn, allowing the background to show through. + +### Hair +The mohawk hair is not visible in the reference image. The hair tiles are +part of the background. For rows 8-15, bit 0 of LCDC is reset, so the +background should not be displayed, and instead color 0 from BGP should be +drawn on the screen. + +### Eyes +The eyes consist of four background/window tiles, and objects overlapping color +0 background pixels. + +The left eye is drawn using the background, and the right eye is drawn using +the window (and also the right edge of the head beside the right eye). At the +bottom of the eye, the WX register is set to an off-screen value, so the window +is hidden until the WX register is set again for drawing the right side of the +chin. + +The background/window tiles for the left half of both eyes have color 0 for the +pupil region of the eye. There are two dark grey colored objects that overlap +the left half of both eyes that have the OBJ-to-BG Priority (bit 7) set in the +OAM flags, so the object will only show through color 0 of the background/ +window tile and replaces the white color. + +The top half of each eye uses tile data from the $8000-8fff region of VRAM. The +bottom half of each eye uses tile data from the $8800-97ff region of VRAM. +The bottom half of the eye uses tiles with index $a1 and $a2 to test that +signed tile indexes are displayed correctly. + +### Moles +The moles are not visible in the reference image, but can be seen in the +failure case images. + +The mole beside the left eye is visible if the background tile data is read +from $8000-8fff instead of $8800-97ff. + +The mole left of the nose is not visible because a blank object with a lower +X-coordinate has priority, even though it is defined later in OAM than the mole +object. + +The mole right of the nose is not visible because a blank object at the same X +coordinate has priority because it occurs earlier in OAM than the mole object. + +### Nose +The nose consists of four objects using the same tile data that is flipped +vertically and/or horizontally. The top left corner of the nose contains the +unflipped tile. + +### Mouth +The mouth consists of eight 8x16 objects. The left and right edges of the mouth +contain unflipped tile data, and other objects use vertically flipped tile +data. + +For the left side of the mouth, the objects specify tile index 12, and the right +side of the mouth specify tile index 13. Because bit 0 of the tile index is +ignored for 8x16 objects, the whole mouth effectively uses tile index 12. + +### Chin +The right side of the chin is drawn using the window. After the right eye was +drawn, the window was hidden by setting WX to an off-screen value. For the +right side of the chin, the WX value is restored to an on-screen value. After +the chin has been drawn, the window is disabled using bit 5 of the LCDC +register so the window does not cover the footer text. + +For the right side of the chin, the window has been updated to use the tile map +from the VRAM beginning at $9800. Because 16 rows of window have already been +drawn for the eye, the right side of the chin is rendered starting from address +$9840. + +### Footer Text +For the footer text, the background is set to use the $9c00-9fff region for +the map data, and tile data is set to come from the $8800-97ff region. + +## Failure Examples +See the table below for some examples of incorrect behaviour and the +corresponding attribute/flag. This is not intended to be an exhaustive list of +all possible failures. + +| Failure Example | Failure Description | Functionality Tested | +| --------------- | ------------------- | -------------------- | +| ![failure image](img/failures/obj-palette.png) | Nose missing | Object Palette (bit 4) | +| ![failure image](img/failures/obj-horizontal-flip.png) | Nose tiles flipped, right eyelash flipped | Object Horizontal Flip (bit 5) | +| ![failure image](img/failures/obj-vertical-flip.png) | Nose tiles filpped, mouth straight, eye whites bottom left wrong | Object Vertical Flip (bit 6) | +| ![failure image](img/failures/obj-to-bg-priority.png) | Eye whites left half wrong | Object to Background Priority (bit 7) | +| ![failure image](img/failures/bg-enable.png) | Hair visible | Background Enable (bit 0) | +| ![failure image](img/failures/obj-enable.png) | Tongue visible | Object Enable (bit 1) | +| ![failure image](img/failures/obj-size.png) | Half of mouth missing | Object Size (bit 2) | +| ![failure image](img/failures/bg-map.png) | Footer missing | Background Tile Map (bit 3) | +| ![failure image](img/failures/tile-sel.png) | Eye whites top left quadrant wrong | Background/Window Tile Data (bit 4) | +| ![failure image](img/failures/win-enable.png) | Half of footer missing | Window Enable (bit 5) | +| ![failure image](img/failures/win-map.png) | Right chin missing | Window Tile Map (bit 6) | +| ![failure image](img/failures/obj-priority-lower-x.png) | Left mole visible | Object Priority Lower X Coordinate | +| ![failure image](img/failures/obj-priority-same-x.png) | Right mole visible | Object Priority Same X Coordinate | +| ![failure image](img/failures/10-obj-limit.png) | Hello World missing exclaimation mark (!) | 10 object per line limit | +| ![failure image](img/failures/8x16-obj-tile-index-bit-0.png) | Half of mouth missing | Bit 0 of tile index for 8x16 objects should be ignored | + +## Credits +Håkon Wium Lie and Ian Hickson for creation of the original +[Acid2](http://www.acidtests.org/) web standards compliance test. diff --git a/img/failures/10-obj-limit.png b/img/failures/10-obj-limit.png new file mode 100644 index 0000000..6915dec Binary files /dev/null and b/img/failures/10-obj-limit.png differ diff --git a/img/failures/8x16-obj-tile-index-bit-0.png b/img/failures/8x16-obj-tile-index-bit-0.png new file mode 100644 index 0000000..c067414 Binary files /dev/null and b/img/failures/8x16-obj-tile-index-bit-0.png differ diff --git a/img/failures/bg-enable.png b/img/failures/bg-enable.png new file mode 100644 index 0000000..f0b16e1 Binary files /dev/null and b/img/failures/bg-enable.png differ diff --git a/img/failures/bg-map.png b/img/failures/bg-map.png new file mode 100644 index 0000000..c887800 Binary files /dev/null and b/img/failures/bg-map.png differ diff --git a/img/failures/obj-enable.png b/img/failures/obj-enable.png new file mode 100644 index 0000000..73fdc19 Binary files /dev/null and b/img/failures/obj-enable.png differ diff --git a/img/failures/obj-horizontal-flip.png b/img/failures/obj-horizontal-flip.png new file mode 100644 index 0000000..bfac273 Binary files /dev/null and b/img/failures/obj-horizontal-flip.png differ diff --git a/img/failures/obj-palette.png b/img/failures/obj-palette.png new file mode 100644 index 0000000..7524a47 Binary files /dev/null and b/img/failures/obj-palette.png differ diff --git a/img/failures/obj-priority-lower-x.png b/img/failures/obj-priority-lower-x.png new file mode 100644 index 0000000..69756ff Binary files /dev/null and b/img/failures/obj-priority-lower-x.png differ diff --git a/img/failures/obj-priority-same-x.png b/img/failures/obj-priority-same-x.png new file mode 100644 index 0000000..ea09ac8 Binary files /dev/null and b/img/failures/obj-priority-same-x.png differ diff --git a/img/failures/obj-size.png b/img/failures/obj-size.png new file mode 100644 index 0000000..e2967b4 Binary files /dev/null and b/img/failures/obj-size.png differ diff --git a/img/failures/obj-to-bg-priority.png b/img/failures/obj-to-bg-priority.png new file mode 100644 index 0000000..9e86cc7 Binary files /dev/null and b/img/failures/obj-to-bg-priority.png differ diff --git a/img/failures/obj-vertical-flip.png b/img/failures/obj-vertical-flip.png new file mode 100644 index 0000000..8b199bb Binary files /dev/null and b/img/failures/obj-vertical-flip.png differ diff --git a/img/failures/tile-sel.png b/img/failures/tile-sel.png new file mode 100644 index 0000000..fbaf1ad Binary files /dev/null and b/img/failures/tile-sel.png differ diff --git a/img/failures/win-enable.png b/img/failures/win-enable.png new file mode 100644 index 0000000..bfbb24c Binary files /dev/null and b/img/failures/win-enable.png differ diff --git a/img/failures/win-map.png b/img/failures/win-map.png new file mode 100644 index 0000000..757fa88 Binary files /dev/null and b/img/failures/win-map.png differ diff --git a/img/footer.png b/img/footer.png new file mode 100644 index 0000000..6d7312f Binary files /dev/null and b/img/footer.png differ diff --git a/img/photo-cgb.jpg b/img/photo-cgb.jpg new file mode 100644 index 0000000..86d0d76 Binary files /dev/null and b/img/photo-cgb.jpg differ diff --git a/img/photo-dmg.jpg b/img/photo-dmg.jpg new file mode 100644 index 0000000..8437471 Binary files /dev/null and b/img/photo-dmg.jpg differ diff --git a/img/reference-cgb.png b/img/reference-cgb.png new file mode 100644 index 0000000..4fbe11b Binary files /dev/null and b/img/reference-cgb.png differ diff --git a/img/reference-dmg.png b/img/reference-dmg.png new file mode 100644 index 0000000..345a6c4 Binary files /dev/null and b/img/reference-dmg.png differ diff --git a/inc/background.asm b/inc/background.asm new file mode 100644 index 0000000..3db92fb --- /dev/null +++ b/inc/background.asm @@ -0,0 +1,18 @@ +BackgroundMap:: + 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 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, $10, $10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 + 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 + 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 + 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 + db 0, 0, 0, 0, 1, 2, 2, 3, $a0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 + db 0, 0, 0, 0, 1, 9, 2, $a1, $a2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 +.end: diff --git a/inc/oam.asm b/inc/oam.asm new file mode 100644 index 0000000..09b2a76 --- /dev/null +++ b/inc/oam.asm @@ -0,0 +1,57 @@ +OAMData:: + ; nose - use OBP1 palette + db $50, $50, $4, $10 + db $50, $58, $4, $30 + db $58, $50, $4, $50 + db $58, $58, $4, $70 + + ; left eye - overlapping background color 0 only, so fills in the whites of the eyes + db $38, $40, $a3, $90 + db $40, $40, $a3, $d0 + + ; right eye - overlapping window color 0 only, so fills in the whites of the eyes + db $38, $60, $a3, $90 + db $40, $60, $a3, $d0 + + ; hello world + db $10, $28, "H", 0 + db $10, $30, "e", 0 + db $10, $38, "l", 0 + db $10, $40, "l", 0 + db $10, $48, "o", 0 + + db $10, $58, "W", 0 + db $10, $60, "o", 0 + db $10, $68, "r", 0 + db $10, $70, "l", 0 + db $10, $78, "d", 0 + db $10, $80, 1, $10 ; this solid white box shouldn't display - 10 sprite limit per line + + ; mouth + db $68, $38, 12, $00 ; sprite size is 8x16 when these sprites are rendered + db $68, $40, 12, $40 ; y-flipped 8x16 sprite + db $68, $48, 12, $40 + db $68, $50, 12, $40 + db $68, $58, 13, $40 ; specify tile 13, but bit 0 of tile index is ignored in 8x16 tile mode + db $68, $60, 13, $40 + db $68, $68, 13, $40 + db $68, $70, 13, $00 + + + db $52, $3d, 9, $00 ; mole + db $52, $3c, 10, $00 ; light grey square - lower x-coordinate so has priority over the mole + ; even though the mole has a lower index in OAM + + db $52, $6c, 10, $00 ; light grey square - same x-coordinate so tile with lower index in OAM + ; has priority + db $52, $6c, 9, $00 ; mole + + + db $38, $3a, 5, $00 ; left eyelash top + db $40, $3a, 6, $00 ; left eyelash bottom + + db $38, $6e, 5, $20 ; right eyelash top + db $40, $6e, 6, $20 ; right eyelash bottom + + db $78, $54, 15, $00 ; tongue +.end: diff --git a/inc/tiles.asm b/inc/tiles.asm new file mode 100644 index 0000000..7ea853c --- /dev/null +++ b/inc/tiles.asm @@ -0,0 +1,136 @@ +TileData:: + db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 + db $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff + db $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00 + + ; 3: one corner of eye + dw `11111133 + dw `11113333 + dw `11133300 + dw `11330000 + dw `13300000 + dw `13300000 + dw `33000000 + dw `33000000 + + ; 4: one corner of the nose + dw `00000001 + dw `00000011 + dw `00000111 + dw `00001111 + dw `00011111 + dw `00111111 + dw `01111111 + dw `11111111 + + ; 5: eye lash top + dw `00002200 + dw `00233200 + dw `02332000 + dw `03320000 + dw `23320000 + dw `33200000 + dw `33200000 + dw `33200000 + + ; 6: eye lash bottom + dw `23300000 + dw `03300000 + dw `02320000 + dw `00230000 + dw `00022000 + dw `00000000 + dw `00000000 + dw `00000000 + + ; filler + db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 + db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 + + ; 9 mole + dw `00000000 + dw `00000000 + dw `00003300 + dw `00033330 + dw `00033330 + dw `00003300 + dw `00000000 + dw `00000000 + + ; 10 mole-cover + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + dw `11111111 + + ; filler + db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 + + ; 12 mouth + db $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff, $ff + db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 + + ; 14 (should not be used for mouth on 8x16 object with tile index 13) + db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 + + ; 15 tongue + db 00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff, $00, $ff + + ; 16 hair + dw `30023002 + dw `32323232 + dw `32323232 + dw `32323232 + dw `32323232 + dw `32323232 + dw `32323232 + dw `32323232 + +.end: + + +TileDataA0:: + ; $a0: top right quadrant corner of eye + dw `33111111 + dw `33331111 + dw `00333111 + dw `22003311 + dw `22200331 + dw `22220331 + dw `22222033 + dw `22222033 + + ; $a1: bottom left quadrant of eye + dw `33000000 + dw `33000000 + dw `13300000 + dw `13300000 + dw `11330000 + dw `11133300 + dw `11113333 + dw `11111133 + + ; $a2: bottom right quadrant of eye + dw `22222033 + dw `22222033 + dw `22220331 + dw `22200331 + dw `22003311 + dw `00333111 + dw `33331111 + dw `33111111 + + ; $a3: eye filling object + dw `33333333 + dw `33333333 + dw `33333300 + dw `33330022 + dw `33300222 + dw `33302222 + dw `33022222 + dw `33022222 +.end: diff --git a/inc/window.asm b/inc/window.asm new file mode 100644 index 0000000..7bf6d50 --- /dev/null +++ b/inc/window.asm @@ -0,0 +1,9 @@ +WindowMap:: + db 3, $a0, 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 + db $a1, $a2, 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 +.end: + +WindowMap9840:: + 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 + 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 +.end: diff --git a/mgblib b/mgblib new file mode 160000 index 0000000..5d829bf --- /dev/null +++ b/mgblib @@ -0,0 +1 @@ +Subproject commit 5d829bf2ffa1447dcfd63c5dab2c44488632617e diff --git a/src/dmg-acid2.asm b/src/dmg-acid2.asm new file mode 100644 index 0000000..86b4971 --- /dev/null +++ b/src/dmg-acid2.asm @@ -0,0 +1,282 @@ +SECTION "mgblib", ROMX +INCLUDE "mgblib/src/hardware.inc" +INCLUDE "mgblib/src/macros.asm" +INCLUDE "mgblib/src/old_skool_outline_thick.asm" +INCLUDE "mgblib/src/display.asm" + + +SECTION "stat_int", ROM0[$48] + jp hl + + +SECTION "boot", ROM0[$100] + nop + jp Main + + +SECTION "main", ROM0[$150] +Main:: + di + ld sp, $cfff + + call ResetDisplay + call LoadFont8000 + + ld hl, OAMData + ld de, _OAMRAM + ld bc, OAMData.end - OAMData + call MemCopy + + ; set the footer tile map + ld hl, $9e80 + ld a, $10 + ld c, 20 +.loop: + ld [hl+], a + inc a + dec c + jr nz, .loop + ld l, $a0 + + ld c, 20 +.loop2: + ld [hl+], a + inc a + dec c + jr nz, .loop2 + + ld hl, BackgroundMap + ld de, $9880 + ld bc, BackgroundMap.end - BackgroundMap + call MemCopy + + ld hl, WindowMap + ld de, $9c00 + ld bc, WindowMap.end - WindowMap + call MemCopy + + ld hl, WindowMap9840 + ld de, $9840 + ld bc, WindowMap9840.end - WindowMap9840 + call MemCopy + + ld hl, TileData + ld de, $8000 + ld bc, TileData.end - TileData + call MemCopy + + ld hl, TileDataA0 + ld de, $8a00 + ld bc, TileDataA0.end - TileDataA0 + call MemCopy + + ld hl, TileData + ld de, $9000 + ld bc, 16 * 3 ; just copy 3 tiles worth of data to mirror between $8000 and $9000 + call MemCopy + + ld hl, TileData + (2 * 16) ; copying the light grey tile + ld de, $9090 ; equivalent location as the mole tile + ld bc, 16 + call MemCopy + + ld hl, FooterTiles + ld de, $9100 + ld bc, FooterTiles.end - FooterTiles + call MemCopy + + + ; enable interrupt for ly=lyc + ld a, $40 + ldh [rSTAT], a + ld a, $57 + ldh [rLYC], a + ld a, 2 + ldh [rIE], a + + ld a, $e4 + ldh [rOBP0], a + ld a, $2c + ldh [rOBP1], a + ld a, $20 + ldh [rSCY], a + ld a, $28 + ldh [rWY], a + ld a, $58 + 7 + ldh [rWX], a + + win_map_9c00 + enable_sprites + bg_tile_data_8000 + lcd_on + + xor a + ldh [rIF], a + + ; schedule first job + ld a, $08 + ldh [rLYC], a + ld hl, LY_08 + + ; initialise the frame counter + ; a source code breakpoint will be triggered after 10 frames + ld b, 10 + + ei + +.forever + halt + jr .forever + +LY_08: + ld hl, rLCDC + res 0, [hl] ; disable background. hides the hair + + ld a, $10 + ldh [rLYC], a + ld hl, LY_10 + reti + +LY_10: + ld hl, rLCDC + set 0, [hl] ; enable background + set 5, [hl] ; enable window + + ld a, $30 + ldh [rLYC], a + ld hl, LY_30 + reti + +LY_30: + ld hl, rLCDC + res 4, [hl] ; bg/win tile data $8800-$97ff + + ld a, $38 + ldh [rLYC], a + ld hl, LY_38 + reti + +LY_38: + ld a, 240 ; disable window by setting WX off-screen + ld [rWX], a + + ld hl, rLCDC + set 4, [hl] ; bg/win tile data $8000-$8fff + + ld a, $3F + ldh [rLYC], a + ld hl, LY_3F + reti + +LY_3F: + ld a, 240 ; disable window by setting WX off-screen + ld [rWX], a + + ld a, $58 + ldh [rLYC], a + ld hl, LY_58 + reti + +LY_58: + ld hl, rLCDC + set 2, [hl] ; object size 8x16 + + ld a, $68 + ldh [rLYC], a + ld hl, LY_68 + reti + +LY_68: + ld hl, rLCDC + res 2, [hl] ; object size 8x8 + res 1, [hl] ; objects disabled - hides the tongue + + ld a, $70 + ldh [rLYC], a + ld hl, LY_70 + reti + + +LY_70: + ld a, $58 + 7 ; enable window by positioning WX on-screen + ld [rWX], a + + ld hl, rLCDC + res 6, [hl] ; window map $9800 + + ld a, $80 + ldh [rLYC], a + ld hl, LY_80 + reti + + +LY_80: + ld hl, rLCDC + set 3, [hl] ; bg map $9c00 + res 4, [hl] ; bg/win tile data $8800-97ff + + ld a, $81 + ldh [rLYC], a + ld hl, LY_81 + reti + + +LY_81: + ld hl, rLCDC + res 5, [hl] ; disable window + set 6, [hl] ; window map $9c00 + + ld a, $82 + ldh [rLYC], a + ld hl, LY_82 + reti + + +LY_82: + ld a, $f3 + ldh [rSCX], a ; position footer correctly + + ld a, $8f + ldh [rLYC], a + ld hl, LY_8F + reti + + +LY_8F: + ld hl, rLCDC + res 3, [hl] ; bg map $9800 + set 4, [hl] ; bg/win tile data $8000-8fff + + ld a, $90 + ldh [rLYC], a + ld hl, LY_90 + reti + +LY_90: + ld hl, rLCDC + set 1, [hl] ; enable objects + + xor a + ldh [rSCX], a ; restore SCX + + ; decrease the frame counter + dec b + jr nz, .skip + + ; source code breakpoint - good time to take a + ; screenshot to compare to reference image + ld b, b + +.skip: + ld a, $08 + ldh [rLYC], a + ld hl, LY_08 + reti + +INCLUDE "inc/background.asm" +INCLUDE "inc/window.asm" +INCLUDE "inc/tiles.asm" +INCLUDE "inc/oam.asm" +FooterTiles:: + INCBIN "img/footer.2bpp" +.end: \ No newline at end of file