In the previous lesson, you learned how to write simple pattern data into the Pattern Generator Table (PGT) and display a single tile on screen.
In this lesson, we’ll take the next big step: building a complete screen map that draws a border around the edges and fills the interior with patterned “spots.”
You’ll see how multiple tile designs combine to form a cohesive graphic, how they’re written into each of the three VRAM pattern banks, and how we use a loop to write an entire Name Table map automatically.
We’re going to construct a screen that looks like this conceptually:
################################
#..............................#
#..............................#
#..............................#
#..............................#
#..............................#
#..............................#
#..............................#
#..............................#
################################
# symbols represent the border tiles (corners, horizontal, and vertical edges).. symbols represent spot tiles, filling the interior of the screen.Each tile (8×8 pixels) is drawn using binary patterns stored in the PGT, and the entire arrangement is defined in a Tile Map — a list of numbers that the program copies into the Name Table.
Just like before, we’re working in Graphics Mode II, where the PGT is split into three banks:
Screen RegionPGT Start AddressVRAM OffsetScreen RowsTop third0×000064 (high byte 64)Rows 0–7Middle third0×080072 (high byte 72)Rows 8–15Bottom third0×100080 (high byte 80)Rows 16–23
This means that each pattern must be defined in every bank if it’s to appear correctly across the whole screen.
We’ll define:
Each one is defined multiple times — once per screen third — so that the graphics are consistent from top to bottom.
LD A,2 : OUT (9),A
LD A,128 : OUT (9),A
LD A,224 : OUT (9),A
LD A,129 : OUT (9),A
As before, these register settings enable Graphics Mode II, giving us access to all three pattern table banks.
LD A,240 ; 11110000 = white ink on black background
OUT (9),A
LD A,135 ; Register 7
OUT (9),A
White text on black background keeps our shapes clear and high-contrast.
We still begin with a blank tile (all zeros) written to all three VRAM sections. This ensures that the background is clean and that any unreferenced tile numbers display as black.
; --- Top, Middle, and Bottom Blank Tiles ---
; (Addresses 64, 72, and 80 high bytes)
; Each written with 8 zero bytes
This step is identical in purpose to the previous lesson — but now it’s a foundation for our custom graphics.
Now we create four distinct patterns: corner, horizontal, vertical, and spot.
Each one has a visual purpose in our final map.
The corner tile frames the outermost points of the border.
Its binary pattern forms a thick, boxy outline:
11111111
10000001
10111101
10100101
10100101
10111101
10000001
11111111
This creates a solid edge with an inner hollow shape.
We write this into:
(The middle section doesn’t need corners because they only appear at the very top and bottom of the screen.)
This tile makes up the top and bottom border edges, stretching across the screen.
Its alternating solid and blank rows create a textured bar:
00000000
11111111
00000000
11111111
11111111
00000000
11111111
00000000
We write this into:
These tiles fill the long horizontal runs of the screen’s border.
The vertical tile forms the left and right walls of the border.
Its repeating diagonal stripe pattern gives a clear textured side edge:
01011010
01011010
01011010
01011010
01011010
01011010
01011010
01011010
We write this tile into:
Because the vertical borders run the entire height of the screen, this tile must exist in all three pattern banks.
This tile forms the repeating “dot” pattern that fills the inside area of the screen.
Its binary layout creates a 4×4 pixel square in the centre of an 8×8 grid:
00000000
00000000
00111100
00111100
00111100
00111100
00000000
00000000
The result is a neat, soft-looking spot that repeats seamlessly across the interior.
We write this into:
so that it can appear anywhere on screen without visual corruption.
LD A, 0
OUT (9),A
LD A, 120
OUT (9),A
LD BC, 768
ClearLoop:
LD A, 0
OUT (8),A
DEC BC
LD A,B
OR C
JR NZ, ClearLoop
Just as before, this step clears all 768 Name Table bytes to the blank tile (pattern 0).
It prepares the grid so we can safely write our map data next.
Now we bring everything together by writing a complete Tile Map to the Name Table.
At the end of the code, you’ll find a data block labeled TileMap: — this is a 32×24 grid of bytes that defines exactly which pattern goes in each tile position.
Each number represents one of our patterns:
Tile IDPatternDescription0BlankBackground1CornerBorder corners2HorizontalTop/bottom border3VerticalLeft/right border4SpotInterior fill
The map starts and ends with corners (1), fills the top and bottom with horizontals (2), and surrounds the sides with verticals (3).
The inner area is filled with spot tiles (4).
Here’s how it works in code:
LD A, 0
OUT (9), A
LD A, 120
OUT (9), A ; Point to start of Name Table
LD HL, TileMap ; HL = address of TileMap data
LD BC, 768 ; 32×24 tiles = 768 bytes
Loop:
LD A, (HL) ; Load next tile number
OUT (8), A ; Write to Name Table
INC HL ; Move to next tile in TileMap
DEC BC ; Decrement counter
LD A, B
OR C
JR NZ, Loop ; Continue until all bytes are written
When the loop finishes, the entire screen’s Name Table has been filled with the contents of TileMap, and the display will show the full bordered pattern.
This loop-based approach is flexible and powerful — you can replace the tile map data block with any arrangement of numbers, and the same loop will draw that new screen layout automatically.
JP $
This halts execution, keeping the display visible indefinitely.
At the bottom of the code, the TileMap defines our full screen layout using pattern IDs. Each DB line defines one horizontal row (32 tiles across).
Here’s the structure:
TileMap:
DB 1,2,2,2,...,2,2,2,1 ; Top border
DB 3,4,4,4,...,4,4,4,3 ; Inner rows with spots and vertical edges
...
DB 1,2,2,2,...,2,2,2,1 ; Bottom border
The repeating use of tile IDs makes it easy to “draw” with numbers.
This method is scalable — later lessons will build on this technique to load maps dynamically from memory or files, enabling scrolling backgrounds and more complex scenes.
ORG 256
; -----------------------
; Enable Graphics Mode II
; ----------------------
; Set Register 0 values
LD A,2
OUT (9),A
LD A,128
OUT (9),A
; Set Register 1 values
LD A,224
OUT (9),A
LD A,129
OUT (9),A
; ---------------------------
; Set Foreground / Background
; ---------------------------
LD A, 240 ; 11110000 (white foreground, black background)
OUT (9), A ; Send to Port 9
LD A, 135 ; 128 (bit 7 set) + 7 (register 7)
OUT (9), A ; Send to Port 9
; -----------------
; Write Blank Tiles
; -----------------
; Top Third Blank Tile
LD A, 0 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 64 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A, 0 ; Load 170 into A
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
; Middle Third Blank Tile
LD A, 0 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 72 ; Load 72 into A register
OUT (9), A ; Send to Port 9
LD A, 0 ; Load 170 into A
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
; Bottom Third Blank Tile
LD A, 0 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 80 ; Load 80 into A register
OUT (9), A ; Send to Port 9
LD A, 0 ; Load 170 into A
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
OUT (8), A ; Send to Port 8
; -------------------
; Write Pattern Tiles
; -------------------
; Top Third Pattern Tiles
; Corner Tile
LD A, 8 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 64 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%11111111 : OUT (8),A
LD A,%10000001 : OUT (8),A
LD A,%10111101 : OUT (8),A
LD A,%10100101 : OUT (8),A
LD A,%10100101 : OUT (8),A
LD A,%10111101 : OUT (8),A
LD A,%10000001 : OUT (8),A
LD A,%11111111 : OUT (8),A
; Horizontal Tile
LD A, 16 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 64 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%00000000 : OUT (8),A
LD A,%11111111 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%11111111 : OUT (8),A
LD A,%11111111 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%11111111 : OUT (8),A
LD A,%00000000 : OUT (8),A
; Vertical Tile
LD A, 24 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 64 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
; Spot Tile
LD A, 32 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 64 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%00000000 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%00000000 : OUT (8),A
; Middle Third Pattern Tiles
; Vertical Tile
LD A, 24 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 72 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
; Spot Tile
LD A, 32 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 72 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%00000000 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%00000000 : OUT (8),A
; Bottom Third Pattern Tiles
; Corner Tile
LD A, 8 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 80 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%11111111 : OUT (8),A
LD A,%10000001 : OUT (8),A
LD A,%10111101 : OUT (8),A
LD A,%10100101 : OUT (8),A
LD A,%10100101 : OUT (8),A
LD A,%10111101 : OUT (8),A
LD A,%10000001 : OUT (8),A
LD A,%11111111 : OUT (8),A
; Horizontal Tile
LD A, 16 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 80 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%00000000 : OUT (8),A
LD A,%11111111 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%11111111 : OUT (8),A
LD A,%11111111 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%11111111 : OUT (8),A
LD A,%00000000 : OUT (8),A
; Vertical Tile
LD A, 24 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 80 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
LD A,%01011010 : OUT (8),A
; Spot Tile
LD A, 32 ; Load zero into A register
OUT (9), A ; Send to Port 9
LD A, 80 ; Load 64 into A register
OUT (9), A ; Send to Port 9
LD A,%00000000 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00111100 : OUT (8),A
LD A,%00000000 : OUT (8),A
LD A,%00000000 : OUT (8),A
; --------------------------------
; Clear Name Table with Blank Tile
; --------------------------------
LD A, 0 ; Low Byte
OUT (9), A ; Send to Port 9
LD A, 120 ; High Byte
OUT (9), A ; Send to Port 9
LD BC, 768 ; Set Counter for table address space
ClearLoop:
LD A, 0 ; Load zero into A register
OUT (8), A ; Send to Port 8
DEC BC ; Decrement BC Counter
LD A, B ; Load B into A register
OR C ; Bitwise OR to compare
JR NZ, ClearLoop ; Jump to start unless BC is zero
; -------------------------------------
; Write Tiles to Name Table / Tile Map
; -------------------------------------
; Point to start of name table
LD A, 0 ; Low Byte
OUT (9), A ; Send to Port 9
LD A, 120 ; High Byte
OUT (9), A ; Send to Port 9
LD HL, TileMap
LD BC, 768
Loop:
LD A, (HL)
OUT (8), A
INC HL
DEC BC
LD A, B ; Load B into A register
OR C ; Bitwise OR to compare
JR NZ, Loop ; Jump to start unless BC is zero
JP $ ; JP Idefinitely
TileMap:
DB 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3
DB 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1
You’ve now taken your first step into tile mapping, the core of classic 8-bit graphics.