ColecoVision#
Open 8bitworkshop IDE
Click here to program the ColecoVision in the 8bitworkshop IDE now!
ColecoVision Specifications#
- Lifespan
1982-1985
- Media
ROM cartridge
- CPU
Zilog Z80
- Memory
16K video RAM, 1K work RAM
- Controllers
two joystick/keypad controllers
- Best-selling game
Donkey Kong (pack-in)
History#
Originally founded as The Connecticut Leather Company, Coleco Industries sold goods like swimming pools and snowmobiles throughout the 1960s. In 1976, it introduced the Telstar console, which used the AY-3-8500 “Ball & Paddle” chip to play variations of Pong. There were difficulties, like a last-minute FCC violation which required the intervention of Ralph Baer, Magnavox, and a ferrite toroid. Coleco would lose $22 million on the Telstar.
Eric Bromley designed a new programmable game system, but RAM was not yet cheap enough for a mass-market product. When prices came down, Coleco’s second console – stubbornly dubbed the ColecoVision – debuted in the summer of 1982. It was designed to deliver arcade experiences in the home, and so having a smash arcade hit would be critical to success.
Seeking game licenses, Bromley visited Nintendo president Hiroshi Yamauchi in Kyoto. While searching for the office bathroom, he discovered a Donkey Kong cabinet in a hallway. The game was not yet well known in the West, and had not yet been discovered by Coleco’s rival Atari. Coleco negotiated a deal for a $200,000 advance and a $2 per unit royalty, delivered on a cocktail napkin – which was saved from the metaphorical trash can by a last-minute appeal to Yamauchi’s daughter, Yoko.
The pack-in Donkey Kong cartridge was impressively faithful to the original. Coleco would sell around two million consoles and publish 145 cartridge titles – including Zaxxon, Gorf, Burger Time, and many lesser-known arcade ports – over the next three years.
The video game crash of 1983 took Coleco’s focus back toward traditional toys like the Cabbage Patch Kids dolls. But due to several missteps, including the poor reception of the Adam computer and talking ALF dolls, the company would file for Chapter 11 bankruptcy five years later.
Hardware#
Unlike the Atari 2600, which features two pieces of custom silicon, the ColecoVision uses off-the-shelf components:
CPU : Zilog Z80A (NEC version) at 3.58 MHz
Video : Texas Instruments TMS9928A Video Display Controller
Sound : Texas Instruments SN76489A Digital Complex Sound Generator
Video RAM : 16 KB
General-Purpose RAM : 1 KB
ROM BIOS : 8 KB
A game cartridge plugs into the top of the unit, and it contains anywhere from 8 to 32 KB of ROM storage.
The ColecoVision also contains a BIOS ROM, a preprogrammed bit of code which runs when the console powers up or is reset. It displays a copyright notice for 12 seconds, and then transfers control to the game cartridge if one is present. The BIOS also contains bitmap fonts and various utility routines.
There is also an Expansion Module Interface at the front of the unit which can accept various plug-in modules to add functionality. Several different modules were produced during the console’s lifecycle – for example, an Atari 2600 compatibility module, and the Adam computer.
Video#
The ColecoVision’s video signal is generated by a TMS-9918A Video Display Controller (VDC) chip. It was also used in the TI-99/4, MSX computers and some early Sega game consoles.
The VDC can generate a 256×192 frame at 60 FPS (50 FPS for PAL). There are several video modes, which we’ll describe in more detail later, but here is a brief summary:
Text : 40 columns by 24 rows of text. Each character is 6x8 pixels, and there are only two colors onscreen (foreground and background).
Graphics 1 : 32 columns by 24 rows of text. Each character is 8x8 pixels, and can have separate foreground and background colors.
Graphics 2 : 32 columns by 24 rows, with 768 different character patterns – in other words, enough to cover the entire screen. Each cell has 8 different foreground/background colors, one for each scanline.
Bitmap : Displays a 64x48 color bitmap.
On the ColecoVision, all colors come from a fixed palette of 16 colors.
Index |
Color |
---|---|
0 |
Transparent |
1 |
Black |
2 |
Medium Green |
3 |
Light Green |
4 |
Dark Blue |
5 |
Light Blue |
6 |
Dark Red |
7 |
Cyan |
8 |
Medium Red |
9 |
Light Red |
10 |
Dark Yellow |
11 |
Light Yellow |
12 |
Dark Green |
13 |
Magenta |
14 |
Gray |
15 |
White |
Most of the graphics modes (except Text) can have sprites overlaid on top of the background. You can have up to 32 moveable 16x16 sprites anywhere on the screen, with the limitation that only 4 sprites may coexist on a single scanline. Each sprite can be assigned its own color from the palette, which is displayed for “on” pixels; all “off” pixels are transparent.
Sound#
Sound is provided by a SN76489 Digital Complex Sound Generator (DCSG) from Texas Instruments. The same chip was also used in several home computers and game consoles, as well as arcade games like Mr. Do!.
It can produce 3 square wave tones simultaneously, each tone generated by a frequency divisor with 1024 possible values. The lack of divisor range means that not many bass notes can be produced; the lowest frequency possible is 109 Hz.
There is also a pseudorandom noise generator, which can either generate noise directly or be used as a frequency divider.
Controllers#
The ColecoVision came with two rectangular controllers with a stubby round joystick and buttons on the side. There is a 12-digit keypad on the controller, into which plastic overlays could be slipped for certain games.
An optional driving controller and a trackball controller were also available via the Expansion Module port.
Memory Map#
A system’s memory map describes which components (sometimes corresponding to physical chips) are connected to a given range of addresses. On many 8-bit systems, there is a single memory map which links the main CPU bus to all other components – e.g. RAM, ROM, and support chips.
The ColecoVision has three distinct memory maps: two are connected to the CPU, and one is behind the Video Display Controller.
On the ColecoVision, the Z80 CPU’s main (address) bus is connected to 1K of RAM, the built-in BIOS ROM, cartridge ROM, and the expansion port:
Start |
End |
Description |
Read/Write? |
---|---|---|---|
$0000 |
$1FFF |
Built-in BIOS ROM |
read |
$2000 |
$5FFF |
Expansion port |
read/write |
$6000 |
$63FF |
RAM, general-purpose |
read/write |
$8000 |
$FFFF |
Cartridge ROM |
read |
The Z80’s IN/OUT instructions access the I/O bus. It controls video and sound, and also reads the controller inputs:
Start |
End |
Description |
Read/Write? |
---|---|---|---|
$80 |
$9F |
Set keypad mode |
write |
$C0 |
$DF |
Video (VDC) registers |
read/write |
$E0 |
$DF |
Set joystick mode |
write |
$E0 |
$FF |
Sound registers |
write |
$E0 |
$FF |
Controllers |
read |
The majority of RAM in the system, 16 KB ($4000 bytes) is directly connected to the Video Display Controller. It cannot be accessed directly by the CPU, but only via the video I/O ports, one byte at a time.
However, the video RAM memory map is not fixed. The programmer can configure the VDC to use different regions of RAM for different purposes. Each of these regions is called a table, and their locations are configured via registers.
There are five different tables:
Image Table – Defines the background tile map, which selects a character out of the pattern table for each cell on the screen.
Pattern Table – Defines an 8x8 (or 6x8 in Text mode) bitmap for each character.
Color Table – Varies between graphics modes, but generally chooses colors for either characters or regions of the screen.
Sprite Attribute Table – Defines position, bitmap, and color for each of the 32 possible sprites.
Sprite Pattern Table – Defines a 16x16 bitmap for each sprite, with 64 bitmaps in each table. There is also an 8x8 sprite mode with 256 bitmaps.
Tables cannot be placed at arbitrary locations in the 16 KB of video RAM; each table has a specific granularity that limits its possible starting location. For example, the Sprite Pattern Table has a granularity of $800, so it can be set to location $0, $800, $1000, or $1800. In some modes, the granularity is limited further.
Table Name |
Granularity |
Description |
---|---|---|
Image Table |
|
Background tile map |
Pattern Table |
|
Character bitmaps |
Color Table |
|
Background color map |
Sprite Attribute Table |
|
Sprite positions and attributes |
Sprite Pattern Table |
|
Sprite bitmaps |
Programming#
Almost all ColecoVision commercial titles were written in Z80 assembly language. This allowed developers to fine-tune each and every byte of their programs. This was critical when fitting games into the small but expensive in the game cartridge. It also allowed for clever optimizations which squeeze the most performance possible out of each frame of animation.
Nowadays, homebrew ColecoVision developers usually write games in either assembler or C, the latter using the SDCC compiler toolchain. Writing in C gives you more functionality per line of code. While it has lower performance and greater code size than a well-written assembly program, you can still write a pretty good game in C.
!!! Note: The 8bitworkshop IDE doesn’t use the original ColecoVision BIOS.
Instead, we replace it with a minimal (yet incompatible) open-source BIOS.
Our C library interacts with the hardware directly and doesn’t need to call BIOS routines, so all our version does it look for a cartridge and start it.
Our BIOS also contains a bitmapped font that can be used by cartridges.
If you want to use your own BIOS, upload it to the IDE with the name coleco.rom
.
Programming the ColecoVision hardware, especially the VDC, is a little tricky, so we’re going to use an open-source C library called LibCV, and its companion library LibCVU. They relieve some of the drudgery of programming I/O ports directly.
We can include these libraries in our source file with the #include
preprocessor directive, like so:
#include "cv.h"
#include "cvu.h"
Graphics Functions#
The majority of LibCV deals with graphics. There are functions for turning the screen on and off:
extern void cv_set_screen_active(bool status);
extern bool cv_get_screen_active(void);
There are functions to change the video mode, and set the background and foreground colors:
void cv_set_screen_mode(enum cv_screenmode mode);
enum cv_screenmode cv_get_screen_mode(void);
void cv_set_colors(enum cv_color foreground, enum cv_color background);
These functions set the location in video RAM of the five tables:
void cv_set_image_table(cv_vmemp loc);
void cv_set_color_table(cv_vmemp loc);
void cv_set_character_pattern_t(cv_vmemp loc);
void cv_set_sprite_pattern_table(cv_vmemp loc);
void cv_set_sprite_attribute_table(cv_vmemp loc);
There are functions to set sprite size, and to get the status of the collision flag (when any two sprites collide) and invalid flag (when there are too many sprites on a scanline):
void cv_set_sprite_big(bool status);
bool cv_get_sprite_big(void);
void cv_set_sprite_magnification(bool status);
bool cv_get_sprite_magnification(void);
bool cv_get_sprite_collission(void);
bool cv_get_sprite_invalid(uint8_t *sprite);
There are several functions that copy data to or from video RAM. There are “fast” and “slow” versions; the “fast” version can be safely used when the screen is inactive (turned off) or the video signal is in VBLANK. The “fast” version can also be used in Text or Multicolor modes, where the VDP doesn’t work as hard.
// copy to video RAM
void cv_memtovmemcpy_slow(const void *src, size_t n);
void cv_memtovmemcpy_fast(const void *src, size_t n);
// copy from video RAM
void cv_vmemtomemcpy_slow(void *dest, size_t n);
void cv_vmemtomemcpy_fast(void *dest, size_t n);
// fill video RAM with bytes
void cv_vmemset_slow(int c, size_t n);
void cv_vmemset_fast(int c, size_t n);
You can also read and write from video RAM byte-by-byte using these functions:
void cv_set_write_vram_address(cv_vmemp address);
void cv_set_read_vram_address(cv_vmemp address);
inline void cv_voutb(const uint8_t value);
inline uint8_t cv_vinb(void);
Controller Functions#
There are functions to read the keypad and joystick ports, and to set the spinner interrupt handler which changes when a spinner is moved:
struct cv_controller_state {
uint8_t keypad;
uint8_t joystick;
};
void cv_get_controller_state(struct cv_controller_state *state, uint_fast8_t controller);
void cv_set_spint_handler(void (* handler)(uint_fast8_t, uint_fast8_t));
Sound Functions#
The sound functions are relatively simple; you can set volume (in decibels) and the frequency divider for each of the three square wave channels. You can also set the noise channel:
extern void cv_set_attenuation(enum cv_soundchannel channel, uint8_t dezibel);
extern void cv_set_frequency(enum cv_soundchannel channel, uint16_t frequency_divider);
extern void cv_set_noise(bool white, enum cv_shift shift);
Interrupt Functions#
The video interrupt handler executes at the end of the video frame, before the VBLANK starts. You can set your own function to execute when this happens:
extern void cv_set_vint_handler(void (* handler)(void));
extern void *cv_get_vint_handler(void);
unsigned char cv_get_vint_frequency(void); // returns 50 or 60 Hz
Utility Functions#
Functions to make setting sprite tables easier:
// Write sprite to display memory. Use the location of the sprite table as base. number should be in [0, 31].
void cvu_set_sprite(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite *sprite);
// Set the x coordinate of the sprite's upper left corner. x will be clamped to [-32, 255]
void cvu_set_sprite_x(struct cvu_sprite *sprite, int x) __preserves_regs(d, e);
int cvu_get_sprite_x(const struct cvu_sprite *sprite) __preserves_regs(b, c, d, e);
// Set the y coordinate of the sprite's upper left corner. y will be clamped to [-32, 207]
void cvu_set_sprite_y(struct cvu_sprite *sprite, int y) __preserves_regs(d, e);
int cvu_get_sprite_y(const struct cvu_sprite *sprite) __preserves_regs(d, e);
// Set them both at once.
void cvu_set_sprite_xy(struct cvu_sprite *sprite, int x, int y);
// Set the sprite's color.
void cvu_set_sprite_color(struct cvu_sprite *sprite, enum cv_color color);
If a sprite has a Y-coordinate of 208, that sprite and all sprites following are hidden.