In the previous installment of this series on Game Boy graphics, I created my first Game Boy tile and exported it. Today, I want to explore exactly what was exported.

The Code

To refresh, here is the assembly code I exported last time:

; EXPORT.Z80
;
; Tile Source File.
;
; Info:
;   Section              : Tiles
;   Bank                 : 0
;   Form                 : All tiles as one unit.
;   Format               : Gameboy 4 color.
;   Compression          : None.
;   Counter              : None.
;   Tile size            : 8 x 8
;   Tiles                : 0 to 0
;
;   Palette colors       : None.
;   SGB Palette          : None.
;   CGB Palette          : None.
;
;   Convert to metatiles : No.
;
; This file was generated by GBTD v2.2

 SECTION "Tiles", HOME

; Start of tile array.
TileLabel::
DB $AA,$1C,$55,$8E,$AA,$C7,$55,$E3
DB $AA,$71,$55,$38,$AA,$1C,$55,$8E

; End of EXPORT.Z80

Z80

The file I exported is named EXPORT.Z80. The Z80 extension denotes the flavor of assembly language used. The Zilog Z80 was a widely popular microprocessor utilized in numerous retro devices.

Interestingly, the Game Boy uses a Sharp LR35902 processor, not a Z80. Although closely related to the Z80, the LR35902 has some differences, which I plan to explore in the future. For now, I can just appreciate that it’s similar enough to the Z80 for my purposes.

Breaking Down the Data

Now that I know what type of data I’m working with, I can start breaking it down.

Comments

Most of the file consists of comments (any line starting with ;). These are ignored by the assembly and meant for human readers. I’ll also be ignoring these for now.

Section and Label

The first non-comment line is SECTION "Tiles", HOME. This is a directive to the assembler to start a new section called “Tiles”. Next is TileLabel::. This is a label that points to the start of the tile data. I don’t need to worry about this until I start working with more assembly.

Tile Data

The encoded tile (00 - lightest green; 01 - light green; 10 - dark green; 11 - darkest green)

Finally, I get to the important part. The tile data is as follows:

DB $AA,$1C,$55,$8E,$AA,$C7,$55,$E3
DB $AA,$71,$55,$38,$AA,$1C,$55,$8E

I know I’m looking at tile data, but what does this actually mean?

DB

DB stands for “Define Byte”. This is a directive to the assembler to define a byte of data. The data after the DB is the data that will be defined (in hexadecimal).

Hexadecimal

Hexadecimal is a base-16 numbering system. This means that each digit can be 0-9 or A-F. This is useful for computers because it is easy to convert between binary and hexadecimal. For example $01 is 00 00 00 01 in binary and $AA is 10 10 10 10. 1 byte (8 bits) is equal to 2 hexadecimal digits.

For more on hexadecimal, including how to convert hexadecimal to binary, check out this article.

Encoding

Given the 2bpp format of the Game Boy, I know that 16 bits (2 hexadecimal digits) are needed to encode 8 pixels (one tile row). Here’s a breakdown of one row from the encoded data:

$AA,$1C => 10 10 10 10, 00 01 11 00

That’s a little confusing because that doesn’t seem to match what I would expect looking at our tile. For example, I don’t see 3 white (lightest green) pixels in the first row. Shouldn’t I expect to see something like this?

01 00 01 10, 11 10 01 00

However 00 00 00 01, 00 00 00 10 is correct. The Game Boy just expects tile data to be encoded differently than I would expect.

MSB and LSB

Before I could fully grasp the encoding process, it was crucial to differentiate between the Most Significant Bit (MSB) and the Least Significant Bit (LSB). The MSB is the bit in a group of bits that represents the highest value, while the LSB represents the lowest value. For instance, in 01, the MSB is 0 and the LSB is ``1`.

When I group MSBs and LSBs together, I see this:

MSB: 00 01 11 00
LSB: 10 10 10 10

Oh interesting! I can see what’s going on here now. The Game Boy actually expects each row to be encoded using the LSBs as the first byte and the MSBs as the second byte. Doing just that gives me this:

10 10 10 10, 00 01 11 00

This matches the binary encoding from above exactly! I could then repeat this process for every row to eventually encode the entire tile.

Why This Encoding?

So why does the Game Boy encode tiles this way? Unfortunately, that knowledge seems to be lost to time. I couldn’t find any definitive answer, however, I can speculate that this may have been easiest for the hardware to read at the time. I’ll have to keep digging to find the answer.

Wrapping Up

I’m glad I was able to understand how the data I exported last time resulted in the tile I drew. While I still want to know why this encoding was chosen, I’m happy that I can at least understand how it works.

Now that I have a better understanding of how tiles are encoded, I think I should start looking at how to actually display these tiles on the Game Boy. Stay tuned for that soon!