
8bitCoding.com has a great description of the layers in the Commander X16:
VERA supports two independent layers to be used. Layer 1 is the default text mode that is active at startup. Layer 0 is placed underneath it and it is disabled by default. They can each have different sizes, point to different tilesets, have different color depth and can be scrolled independently.
In this way, you can have a sprite between the layers or on top. This makes it easy to move sprites behind and in front of certain tiles. You can also use the top layer for a HUD.
The default screen is configured as 128 tiles wide and 64 tiles high and tiles are 8 x 8 pixels. If we do some math on these numbers we see that that would translate to 1024 x 512 pixels, which of course is larger than what can be displayed on the monitor (640×480).
In memory, the tile data is staggered by two bytes. This is laid out as:
Tile, tile colour, tile, tile colour, tile, tile colour, …etc…
Each tile can be 8 or 16 pixels high and 8 or 16 pixels wide. This gives combinations: 8×8, 8×16, 16×8 and 16×16. Colours can be 1-bit, 2-bit, 4-bit or 8-bit. The last 4 bits of the Layer 1 Config Register #20 ($9F34) determine the mode. Affected bits are below (unaffected bits are marked with an ‘x’):
Available tile modes:
- 1 bpp – Choose one foreground colour out of the first 16 colours in the current palette and one background colour out of the first 16 colours in the current palette. Use up to 256 tiles. Config = xxxx0000.
- 1 bpp – Choose one foreground colour out of all 256 colours in the current palette. The background is always transparent. Use up to 256 tiles. Config = xxxx1000.
- 2 bpp – Choose three foreground colours out of columns 1,2 and 3 in the current palette. Background is always transparent. Use up to 1024 tiles, with tile flipping. Config = xxxxx001.
- 4 bpp – Choose 15 foreground colours within the same line in the current palette. Background is always transparent. Use up to 1024 tiles, with tile flipping. Config = xxxxx010.
- 8 bpp – Choose 255 foreground colours from the whole palette except colour #0. Background is always transparent. Use up to 1024 tiles, with tile flipping. Config = xxxxx011.
The modes are selected from the Config Register #20. Bit 2 in the config sets the Bitmap mode.
Bits 6 & 7 of the Config Register set the tile map’s height. Bits 4 & 5 set the tile map’s width.
Available map modes:
- 00 – 32 tiles wide or high.
- 01 – 64 tiles wide or high.
- 10 – 128 tiles wide or high (default).
- 11 – 256 tiles wide or high.
Each layer can have 16 possible dimensions: 32×32 tiles, 32×64, 32×128, 32×256, 64×32, 64×64, 64×128, 64×256, 128×32, 128×64, 128×128, 128×256, 256×32, 256×64, 256×128 and 256×256 (probably not enough memory available for this mode).
Bit 3 is used to set the 1 bit per pixel modes – 16 colors or 256 colors available per tile.
Register #21 ($9F35) sets the base address of our tile map. Register #22 ($9F36) sets the base address of our tiles.
If you downloaded the TutorialsAssets.zip file from the downloads page you will see: tileset.bin, tileset-palette.bin, tilemap.bin as well as tiled-tilemap.tmx and tileset.png
You can use the tiled-tilemap.tmx file with the tileset.png to load and test our demo Tilemap in Tiled. I won’t go into detail with how to load in tilemaps and png tilesheets into Tiled. There’s a lot of information about that already. You can download a Tiled extension to export a Tiled tilemap in the Commander X16 tilemap format. I’ve already done that as the file tilemap.bin which we will be using.
You can export the tileset.png Tilesheet data with X16PngConverter which we used earlier for our bitmap. Here’s the command-line:
X16PngConverter.exe images\Tileset.png -tiles -h 16 -w 16
First, we tell it we are exporting tiles this time which each have a height of 16 pixels and a width of 16 pixels. The converter program will output tileset.bin and tileset-palette.bin
Our png images are in 8bpp mode (256 colours). Now, we need code to load in the tiles, palette, tilemap and set the correct Commander X16 mode to display them all. Change your main section:
main {
sub start() {
void diskio.vload("tileset.bin", 0, $0000)
void diskio.vload("tileset-palette.bin", 1, $fa00)
void diskio.vload("tilemap.bin", 1, $b000)
cx16.VERA_CTRL = 0 ; Select Data Register 0
cx16.VERA_DC_BORDER = 0 ; the palette index for the non-active area of the screen
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00100000 ; enable only layer 1
cx16.VERA_DC_HSCALE = 64 ; 64 tiles across - "zooms" in
cx16.VERA_DC_VSCALE = 64 ; 64 tiles down - "zooms" in
cx16.VERA_L1_CONFIG = %00010011 ; Tile mode and 64x32 tiles, 4bpp
cx16.VERA_L1_MAPBASE = ($1B000 >> 9) as ubyte ; Tilemap was loaded into $1b000
cx16.VERA_L1_TILEBASE = %00000011 ; 16x16 pixel tiles
repeat {}
}
}
The repeat line is just a null-loop so we don’t return to BASIC and show a flashing cursor.
Note: Always use lower-case text for file names otherwise the compiler will convert the characters to PETSCII
The first lines load in the tileset, next the palette and finally the tilemap into their respective memory locations.
The next set of lines set up the VERA graphics chip modes and configurations for Layer #1 (L1). I have commented each line to help explain what it does. We’re only writing to Layer #1 at this stage so we set that here.
If you Build the file above with the tile files in your Project folder you should see the following image:

That’s all there is to creating and displaying a tilemap!
Now, let’s try some basic animation. We’ll animate the water over 2 different tiles to make it look like it’s shimmering.
main {
sub start() {
void diskio.vload("tileset.bin", 0, $0000)
void diskio.vload("tileset-palette.bin", 1, $fa00)
void diskio.vload("tilemap.bin", 1, $b000)
cx16.VERA_CTRL = 0
cx16.VERA_DC_BORDER = 0
cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00100000 ; enable only layer 1
cx16.VERA_DC_HSCALE = 64
cx16.VERA_DC_VSCALE = 64
cx16.VERA_L1_CONFIG = %00010011 ; Tile mode and 64x32 tiles, 8bpp
cx16.VERA_L1_MAPBASE = ($1B000 >> 9) as ubyte
cx16.VERA_L1_TILEBASE = %00000011 ; 16x16 pixel tiles
ubyte t
uword x,y
const ubyte screen_width = 64
const ubyte screen_height = 32
repeat {
for y in 0 to screen_height {
for x in 0 to screen_width*2 step 2 {
t = cx16.vpeek(1,$b000+(screen_width*y*2)+x)
if (t == 1) {
cx16.vpoke(1,$b000+(screen_width*y*2)+x,6)
}
if (t == 6) {
cx16.vpoke(1,$b000+(screen_width*y*2)+x,1)
}
}
}
sys.wait(20)
}
}
}
We need to iterate over all tiles in the Tilemap, remembering to skip every second value in memory as these denote the colour data and we’re not changing that. Obviously we could optimize this by not even looking at data in the top and bottom rows where there can only be static bricks and other optimizations, but this is just to give you an idea.
If the tile found has the value ‘1’ which is our first frame of animation, then change it to ‘6’. If it’s 6, make it 1. We throw in a sys.wait() to slow down the animation for our testing as it’s quite fast.
The repeat directive just says to do it infinitely.

Comments