ColecoVision

Development

Tutorial

Introduction to sdcc

ColecoVision system

Playing music

Hardware

Homebrew kits

Homebrew kit CV

Homebrew kit CVs

Software

libcv and libcvu

png2cv

png2cvs

abc2cvm

cvmtuning

compression utilities

Games

colecovision.eu

ColecoVision

How to buy

STM8

MCS-51

LLVM+SDCC

Contact

The ColecoVision video game system

Introduction

Writing ColecoVision games requires some deeper knowledge of the system. This tutorial is meant to provide an overview. Future tutorials will cover individual components more in-depth.

Fortunately the ColecoVision was designed using off-the-shelf parts so that documentation is available. It's heart are a Zilog Z80 processor, a TMS TMS9928A or TMS9929A graphics chip and a TI SN76489 tone generator. These chips are driven by the 3.579545 Mhz main clock. The ColecoVision contains 1 KB of DRAM for the processor and 16 KB DRAM as graphics memory. The BIOS resides in an 8 KB ROM. All voltages in the digital part are TTL compatible. The ColecoVision connects to the outside world through power input, controller ports, video output, the cartridge slot and an expansion connector. Those interested in more details should have a look at Daniel Boris' schematics.

The Z80 is the processor that achieved the highest market share ever; It is an enhanced 8 bit processor, which has a 16 bit address and I/O space (In the ColecoVision only 8 bits are used for I/O addresses though). due to it's popularity a lot of information is available. Thomas Scherrer has collected some; to those interested in assembly programming (which can be useful for optimizing some inner loops in game which are otherwise written in C) I suggest the book "Programming the Z80" by Rodnay Zaks.

libcv and libcv

libcv aims at exposing all of the ColecoVision's hardware functionality to the C programmer. It already does a rather good job at doing so with the only missing major functionality being the wheel on the super actioncontrollers. However flexibilty libcv comes at a price: Some of libcv's interfaces are not very user-friendly, requiring some effort even for common routine tasks. Therefore libcvu exists: It provides userfriendly interfaces for tasks such as manipulating sprites or playing music.

Library functions are grouped by functionality: cv_graphics.h contains graphics-related functions, cv_sound.h and cv_input.h are for sound and input. cv.h includes all three and has some generic functionality. libcvu is organized in a similar way.

The vertical retrace interrupt

The graphics chip signals when it's done drawing a frame via an interrupt. This interrupt is called the vertical retrace interrupt (vint) since it's raised when the vertical retrace starts on a connected TV or the non-maskable interrupt (NMI) since in the ColecoVision this interrupt line is connected to the Z80's NMI input.

This interrupt is important to the programmer sinceit's the only way of measuring time on the ColecoVision. It occours every 60 times per second on a ColecoVision with a TMS9928A graphics chip (ColecoVisions in the US and Canada, designed to work with NTSC TVs), 50 times per second in case the ColecoVision has a TMS9929A (All others, mostly European ColecoVisions, probably Brazilian Splicevisions, designed to work with PAL or SECAM).

libcv exposes this interrupt through three functions: cv_get_vint_frequency() can be used to find out how often the vint occours. cv_set_vint_handler() registers a callback function that is called whenever a vint occours (to unregister the callback function use cv_set_vint_handler(0)). cv_get_vint_handler() returns a pointer to the curretnly registered callback handler. Callback handlers have to be functions returning void that take no arguments.

Suppose you write a game that needs has an update() function where everything like input processing and display update happens. Depending on the game situation update() will take up to a thirtyth of a second. You want your game to run at a constant speed and framerate. This could be done using the following code:


#include "cv.h"

volatile unsigned char counter;

extern void init(void);
extern void update(void);

void tick(void)
{
	counter++;
}

void main(void)
{
	init();	// Your initialization code
	cv_set_vint_handler(&tick);
	for(;;)
	{
		while(counter < 2);
		counter = 0;
		update();	// Your game function
	}
}

The cursor and cursor32 demos included with libcv/libcvu use the vertical retrace interrupt in a similar way.

In case you want to use library functions from both the vint handler and other code please chek the information on reentrany in the headers.

The memory map

The standard (no expansion modules or multicarts) ColecoVision memory map looks like this:

0x0000 - 0x1FFFBIOS
0x2000 - 0x5fffUnused
0x6000 - 0x7fffRAM
0x8000 - 0x8000Cartridge ROM

Though the ColecoVision has only 1 KB of RAM it's mapped 8 times so that the mapping uses 8K of address space. The BIOS is irrelevant to the programmer using libcv/libcvu expect for the ColecoVision's builtin font.

sdcc invocation

The command line you use to invoce sdcc depends on the path to libcv/libcvu. Typical lines look like this: sdcc -mz80 --std-c99 -c "-I../../include/" main.c
This will compile main.c into main.o (-mz80 tells the compiler to generate code for the Z80 processor, --std-c99 speciefies conformity to the ICO C99 standard, -c makes sdcc generate an object file instead of the final image).

Once you've created some objects files you'll want to link them together (command line depending on the path to libcv/libcvu): sdcc -mz80 --no-std-crt0 --code-loc 0x8100 --data-loc 0x7000 "../../bin/libcvu.lib" "../../bin/libcv.lib" "../../bin/crt0.o" *.o
--no-std-crt0 tells sdcc no to use the standard crt0.o (we need the ColecoVision-specific one that comes with libcv) --code-loc 0x8100 makes sdcc assume that the code starts at 0x8100 (we leave some space at 0x8000 for the startup code) --data-loc 0x7000 tells sdcc that the ColecoVision's RAM is located at 0x7000.

You'll probably want to automate sdcc invocation in your projects. Have a look at the Makefiles that come with the libcv/libcvu demos.