(almost) Z80 Assembly programming for the Gameboy and Gameboy Color

The Gameboys do not use a Z80... some people say they do, but those people are wrong! it has MANY features of a Z80... but MANY others are weird... and some are even BUGGY!

So why might we want to use it... well,  the gameboy+GBC sold 118 MILLION!... compared to the ZX spectrum's puny 5 million... the gamegears 10 million, the Master system's 13 million... the Gameboy gives the 'real z80' systems a spanking!

We can't use a normal Z80 assembler to develop for it, but Vasm in 'OldStyle' mode will compile for it, just use the switch '-gbz80' and it will compile compatible code!
The Gameboy Color is just a Gameboy with a few 'power ups', The best thing is, if we limit ourselves a bit, we can write games that have full color on the GBC, but still play the same on the Classic Gameboy!

Lets take a look at the GB and GBC specs!

Specs:
Gameboy Gameboy Color
Cpu 4mhz 8mhz
Ram 8k 32k
Vram 8k 16k
Resolution 160x144 160x144
Max Tiles 256 (8x8 px) - 360 onscreen 512 (8x8 px) - 360 onscreen
Max Sprites 40 (8x8 px 10 per line) 40 (8x8 px 10 per line)
Colors 4 4 per palette - 8 palletes (0-7) from 32768 colors
Sound chip GBZ80 PAPU GBZ80 PAPU





It's Z80... but not as we know it!


So what's actually different, well, first you've got less registers...  the 'GBZ80' (as we'll call it) has no shadow registers, I or R... and no index registers either!


  Normal Registers Shadow Registers
Accumulator A
A'
flags F F'
HighLow Memory Location H L H L
ByteCount B C B C
DEstinaton D E D E
Indirect X - IX IXH IXL

Indirect Y - IY IYH IYL

         
Program Counter   PC    
Stack Pointer   SP    
Refresh   R    
Interrupt point   I    


LDIR type commands are gone, but we can always fake them!

Commands that load 2 bytes from a memory address like LD BC,(&1234) do not exist, we have to read in the bytes separately

There's no IN or OUT commands, not that it matters, as devices are memory mapped, so we just read or write to them in their memory locations.

oh and thanks to a bug, INC xx and DEC xx with BC, DE or HL can corrupt the sprite memory, just for good measure!

The HALT command also has a quirk!, if interrupts are disabled, the command will skip, however the CPU also skips the following command, so put a NOP after HALT

We do have some new exciting commands... SWAP A will swap the top nibble and bottom nibble of A (or any other register!)

LD ($FF00+C),A ... will use C as part of the address to write to - this is the equivalent of OUT (C),a... as the memory mapped devices are in the &FF00-&FF80 range.

We also have LDI for Load and Increment, and LDD for load and decriment... it kind of makes up for losing LDIR!

I've started making a Cheatsheet, which already contains all the new and changed commands...but if you're careful, and only use commands supported by the Z80 and GBZ80, you can create common code that can compile for either system!

There are interrupts, but there is no interrupt mode 1 or 2... RST0-7 exist, but &0038 is not called by any interrupts... GBZ80 interrupts call addresses &0040-&0060 in rom.

Console graphics hardware - Tiles and Sprites!
This section is a general description, and not SMS/GG specific, skip to the next chapter if you know the concept of tiles and sprite layers!

The Gameboy,Gamegear and Mastersystem screens do not work like they do on computers like the CPC
Graphics are not just 'bytes' in a memory address...  The screen is made up of a 'Tile Layer' and a 'Sprite Layer'

To explain Tiles and sprites, lets look at our imaginary game shown to the right 'The Super Yuusha Siblings', on a theoretical game system the 'GameChibi'... Just to be very clear, we looking at this as a concept, not the actual layout of the gameboy!

Looking at our example, We have a level with some grass, blocks, and some collectable 'stars'... our hero, Yume is controlled by the player...
The screen is made up of the Tile layer, and the Sprite Layer,

Usually Sprites are drawn above the Tiles... but sometimes they may be drawn below.

It's also possible we could use sprites for the stars.. but sprites are very limited, so the object doesn't move, then tiles will do the job... we can even animate the stars by switching the tile between different patterns
The tile array on the systems we'll be looking at is made up of 8x8 tiles... the array is a 'grid' of these tiles, so the tiles must line up, a block cannot be at a 'half way boundary'

Tiles are defined by a number (usually 0-255)... we define the bitmap (image) data for that tile (we'll call it a pattern), then tell the hardware what positions in the tile array to use that pattern.

In our example, the black background is pattern 0 ... the blocks are pattern 1... the grass is pattern 2... and the stars are pattern 3

Our 'GameChibi' console has a tile array of 8x8... and 64 bytes is used to define the tile grid...
So to define the stars, we need to set memory locations 10,20 and 15 of the tile array to byte '3'

A real system usually has a tile array bigger than the screen (maybe just by one row and one coumn)... this is to allow smooth scrolling of the screen, where two tiles are 'half shown'

Now in the case of our 'GameChibi' system, with it's 64 tile screen, and 256 pattern definitions, we could just set every visible tile to a different pattern, and treat the screen as a plain bitmap again... We can do that on the MSX1, but unfortunately the Gameboy and Mastersystem have too few tiles for their screen size, so some parts of the screen must contain the same tile!
Because our system is using hardware sprites, we have to design our game sprites in a way that can be drawn with the hardware sprites... for example lets look at our Yume sprite... if our 'GameChibi' used 8x8 hardware sprites, we would have to use 48 of them to make this image!... we can save 6 (marked green)... these have no data, so we can just not draw them...

When it comes to moving our character, the software will have to move the hardware sprites all together, so the user does not realise they are made up of many sprites!... on systems with more onscreen colors than sprite colors, two or more sprites may be overlapped to make the sprite appear more colorful

Most systems will have one color (usually 0) which marks the transparent colour.

but there is a problem! with software sprites on a bitmap screen, we can draw as much as we want, it will just get slow.... but with hardware sprites, we have a fixed limit of how many sprites can be shown onscreen at once! sounds bad? well actually it's worse, even though a system like the gameboy can show 40 sprites onscreen, there can only be 10 on a line... if more than 10 appear on the same line, some will flicker, or not appear... there's nothing we can do about it, we just have to design our game to avoid this problem!

The Gameboy Color, for extra power!
The gameboy color has many enhancements,
We can switch the CPU into high speed mode, for twice the CPU power and we have extra ram banks we can page in.

Most importantly the GBC adds more graphics ability, with twice the tile definitions (512) and 8 'palettes' of four colours

Colour palettes are defined with a 5 bits per channel in the format  -BBBBBGG GGGRRRRR

Turning on the 'Second bank of tiles' (the extra 256) and setting the color palette is done by paging in the second 'GBC only' Vram Bank

Gameboy Cartridge Rom format - and Interrupt calls!
The cartridge is loaded into the system memory as the ROM... The first &160 bytes of the cartridge contain the RST calls and GBZ80 Interrupt calls

Next come the header, which tells the gameboy what the cartridge contains... there is also a checksum, which must be correct for the game to work on a real gameboy - though it should work on emulators without it! (the tool rgbfix.exe will work out the checksum for you!)

A note on the interrupts between &0040-&0060:
Interrupts can be enabled or disabled as needed, but it's best to put a  'RETI'  (Return and enable interupts) at &0040-&0060

From To Meaning
0000 0007 Z80 RST0
0008 000F Z80 RST1
0010 0017 Z80 RST2
0018 001F Z80 RST3
0020 0027 Z80 RST4
0028 002F Z80 RST5
0030 0037 Z80 RST6
0038 003F Z80 RST7
0040 0047 Interrupt:Vblank
0048 004F Interrupt:LCD-Stat
0050 0057 Interrupt:Timer
0058 005F Interrupt:Serial
0060 0067 Interrupt:Joypad
0068 00FF unused
0100 0103 Entry point (start of program)
0104 0133 Nintendo logo (must match rom logo)
0134 0142 Game Name (Uppercase)
0143 0143 Color gameboy flag (&80 = GB+CGB,&C0 = CGB only)
0144 0145 Game Manufacturer code
0146 0146 Super GameBoy flag (&00=normal, &03=SGB)
0147 0147 Cartridge type (special upgrade hardware) (0=normal ROM)
0148 0148 Rom size (0=32k, 1=64k,2=128k etc)
0149 0149 Cart Ram size (0=none,1=2k 2=8k, 3=32k)
014A 014A Destination Code (0=JPN 1=EU/US)
014B 014B Old Licensee code (must be &33 for SGB)
014C 014C Rom Version Number (usually 0)
014D 014D Header Checksum - ‘ones complement’ checksum of bytes 0134-014C
not needed for emulators
014E 014F Global Checksum – 16 bit sum of all rom bytes (except 014E-014F)
unused by gameboy
0150 Game Code!
Gameboy Memory Map
The Rom cartridge (and its header) take up the first &8000 bytes of memory,

The 8k of ram is accessible at &C000-&DFFF... a 'shadow copy' is also at &E000-&FDFF (some cartridges have extra ram at this address)

0000 3FFF 16KB ROM Bank 00 (in cartridge, fixed at bank 00)
4000- 7FFF 16KB ROM Bank 01..NN (in cartridge, switchable bank number)
8000 8FFF VRAM: Tiles / Sprites
9000 97FF VRAM: Tiles Alt
9800 9BFF VRAM: Tilemap 1
9C00 9FFF VRAM: Tilemap 2
A000 BFFF 8KB External RAM (in cartridge, switchable bank, if any)
C000 CFFF 4KB Work RAM Bank 0 (WRAM)
D000 DFFF 4KB Work RAM Bank 1 (WRAM) (switchable bank 1-7 in CGB Mode)
E000 FDFF Same as C000-DDFF (ECHO) (typically not used)
FE00 FE9F Sprite Attribute Table (OAM) (Can’t change during screen redraw)
FEA0 FEFF Not Usable
FF00 FF7F I/O Ports
FF80 FFFE High RAM (HRAM) (Stack)
FFFF FFFF Interrupt Enable Register


Hardware ports - AKA 'Where's my OUT command gone?'
As mentioned before, the Gameboy has no IN or Out commands, there is a bank of hardware regsiters memory mapped between &FF00 and &FF80... just write or read from these memory locations to have the hardware effect... we'll cover the details of these in later tutorials
Group Address Meaning Notes
Timer FF06 TMA - Timer Modulo (R/W)
Timer FF07 TAC - Timer Control (R/W)
INT FF0F IF - Interrupt Flag (R/W)
Sound FF10 NR10 - Channel 1 (Tone & Sweep) Sweep register (R/W)
Sound FF11 NR11 - Channel 1 (Tone & Sweep) Sound length/Wave pattern duty (R/W)
Sound FF12 NR12 - Channel 1 (Tone & Sweep) Volume Envelope (R/W)
Sound FF13 NR13 - Channel 1 (Tone & Sweep) Frequency lo (Write Only)
Sound FF14 NR14 - Channel 1 (Tone & Sweep) Frequency hi (R/W)
Sound FF16 NR21 - Channel 2 (Tone) Sound Length/Wave Pattern Duty (R/W)
Sound FF17 NR22 - Channel 2 (Tone) Volume Envelope (R/W)
Sound FF18 NR23 - Channel 2 (Tone) Frequency lo data (W)
Sound FF19 NR24 - Channel 2 (Tone) Frequency hi data (R/W)
Sound FF1A NR30 - Channel 3 (Wave Output) Sound on/off (R/W)
Sound FF1B NR31 - Channel 3 (Wave Output) Sound Length
Sound FF1C NR32 - Channel 3 (Wave Output) Select output level (R/W)
Sound FF1D NR33 - Channel 3 (Wave Output) Frequency's lower data (W)
Sound FF1E NR34 - Channel 3 (Wave Output) Frequency's higher data (R/W)
Sound FF20 NR41 - Channel 4 (Noise) Sound Length (R/W)
Sound FF21 NR42 - Channel 4 (Noise) Volume Envelope (R/W)
Sound FF22 NR43 - Channel 4 (Noise) Polynomial Counter (R/W)
Sound FF23 NR44 - Channel 4 (Noise) Counter/consecutive; Inital (R/W)
Sound FF24 NR50 - Channel control / ON-OFF / Volume (R/W)
Sound FF25 FF25 - NR51 - Selection of Sound output terminal (R/W)
Sound FF26 NR52 - Sound on/off
Sound FF30-
FF3F
Wave Pattern RAM
LCD FF40 LCDC - LCD Control (R/W)
LCD FF41 STAT - LCDC Status (R/W)
Tile FF42 $00 ; SCY – Tile Scroll Y
Tile FF43 $00 ; SCX – Tile Scroll X
LCD FF44 LY - LCDC Y-Coordinate (R) - LCD Y Line (0-153 144+ are V-Blank)
LCD FF45 LYC - LY Compare (R/W)
RAM FF46 DMA - DMA Transfer and Start Address (W)
Tile FF47 BGP - BG Palette Data (R/W) - Non CGB Mode Only
Sprite FF48 OBP0 - Object Palette 0 Data (R/W) - Non CGB Mode Only
Sprite FF49 OBP1 - Object Palette 1 Data (R/W) - Non CGB Mode Only
Tile FF4A WY - Window Y Position (R/W) Default = 0
Tile FF4B WX- Window X Position minus 7 (R/W) Default = 7
CPU FF4D KEY1 - CGB Mode Only - Prepare Speed Switch
VRAM FF4F VBK - CGB Mode Only - VRAM Bank
COM FF56 RP - CGB Mode Only - Infrared Communications Port
Tile FF68 BCPS/BGPI - CGB Mode Only - Background Palette Index
Tile FF69 BCPD/BGPD - CGB Mode Only - Background Palette Data
Sprite FF6A OCPS/OBPI - CGB Mode Only - Sprite Palette Index
Sprite FF6B OCPD/OBPD - CGB Mode Only - Sprite Palette Data
RAM FF70 SVBK - CGB Mode Only - WRAM Bank (bits 0-3 =0-2)

Bankswitching on cartridges with MBC1+
Larger cartridges can have more than 32k rom, and even extra RAM built into them (With battery backup!)
We switch cartridge RAM/ROM bank by writing to specific address ranges within the 'ROM'... this tells the cartridge to change bank...
Good example addresses are shown below... though actually a range of addresses will have the same effect
MBC1 Bank Swapper
0000 (Write) – Ram enable (&0A)
2000 (Write) – Rom Bank Number
3000 (Write) – Bit 8 of MBC5 ROM Bank
4000 (Write) – Ram Bank Number
6000 (Write) – Rom/Ram Mode Select

Gameboy Joystick port
Joypad reading is all done with memory address &FF00

Only Bits 0-3 in this address contain the state of the buttons, we first need to select which half of the joystick we want to read.

If we write %11101111 to &FF00 (Bit 4 is zero) ... we will select the diirection controls... and the next read from &FF00 will get Down, Up, Left, Right in bits 0-3

If we write %11011111 to &FF00 (Bit 5 is zero) ... we will select the button controls... and the next read from &FF00 will get Start, Select, Button B, Button A in bits 0-3
Address Bit Purpose
&FF00 7 Unused
6 Unused
5 Read Buttons
4 Read Directions
3 Down Start
2 Up Select
1 Left Button B
0 Right       Button A

Gameboy Sprite Memory
Sprite Data is stored from &FE00 onwards, there are 40 sprites, and each definition uses 4 consecutive bytes...

For Example, Sprite 0's bytes are highlighted in black... it has a Y co-ordinate, an X co-ordinate, a Tile Number, and tile Attributes

Y and X are offset, so you can have a sprite partially off the screen, You need to set XY to (8,16) to get the top corner of the screen (0,0)

Attributes:  
7      6           5           4      3   2     1     0  
Tile-Sprite
Priority
Y-flip X-flip GB-Pal CGB-Vbank CGB-Palette



Gameboy and Gameboy Color Programming Tutorials:
P9 - Tilemap graphics on the Gameboy and Gameboy Color

General Z80 Assembly Tutorials:
B. Beginner series - Learn the basics
A. Advanced series - In more detail
M. Multiplatform series - programming methods that work on all systems



Visit www.ChibiAkumas.com to get my games and their source code! | Support me on patreon