This is part of a series of posts analysing the Chip-8 interpreter on the RCA COSMAC VIP computer. These posts may be useful if you are building a Chip-8 interpreter on another platform or if you have an interest in the operation of the COSMAC VIP. For other posts in the series refer to the index or instruction index.
INSTRUCTION GROUP: FX29
Load I with address of sprite for the character in VX
The only means of getting data onto the Chip-8 display is using the DXYN instruction to display a sprite. So Chip-8 has a character set, consisting of all the hexadecimal digits, in which each digit is stored as a pre-defined sprite, allowing the programmer to use the DXYN instruction to display these.
The character set sprites are stored in the ROM. Each character is just four pixels wide. As Chip-8 sprites are one byte wide, the characters are aligned to the left side of the sprite and the rightmost four pixels of the sprite are set to 0. Each character is five pixels high. If they were stored in a linear fashion, this would require 80 bytes of memory (16 characters, each consuming 5 bytes). Today we wouldn’t worry about losing 80 bytes any more than we’d worry about a penny that slipped through our fingers and rolled down a drain. However, when your ROM is only 512 bytes, every byte suddenly becomes significant. So the Chip-8 character set sprites were designed in such a way that the data for some characters overlaps. Here’s what that looks like:
This little trick cuts the space requirement from 80 to 51 bytes. Of course the advantage of having the characters stored linearly, with each occupying its own five-byte space, would be that you could calculate the start address of a sprite simply by multiplying the required digit by five and adding this to the base address. With the sprites compressed the way they are in the COSMAC VIP that’s not an option, so the ROM also contains a look-up table with the low-order byte of the address of each sprite. This adds an overhead of 16 bytes. Even so, this still saves 13 bytes over the standard way of doing things. That doesn’t sound like it would be worth the effort until you realise that 13 bytes is 2.5% of the total ROM! This really is a case of having to make every byte count.
Chip-8 provides an instruction, FX29, that puts the address of the sprite for the character in VX into the index variable I. This is then ready to be used with a DXY5 instruction to display the character on screen at coordinates X, Y. It works by getting the least significant digit of VX and using this as an offset into the look-up table. The value of the relevant byte in the look-up table is then combined with the high order byte 0x81 to create the full address to the start of the sprite data for the requested character.
Here’s the code for that routine:
|Address (hex)||Code (hex)||Labels||Assembly||Comments|
|0129||E6||FX29:||LDI 0x81||Both the look up table and the sprite data are located in the ROM in page 0x81|
|012B||BA||PHI A||Store this in the high order byte of I (RA.1)|
|012C||06||LDN 6||Get the value in VX (R6)|
|012D||FA 0F||ADI 0x0F||Apply a mask to save just the least significant digit|
|012F||AA||PLO A||I now points to the correct entry in the look-up table|
|0130||0A||LDN A||Get the low-order byte of the sprite address from the look-up table|
|0131||AA||PLO A||I now points to the start of the data for the correct sprite|
|0132||D4||SEP 4||Return to the fetch and decode routine|
Execution time for this routine is 16 machine cycles (72.64 microseconds). As this is an FXXX instruction, the small overhead for the second stage decoding of these instructions needs to be added. See this earlier post for details.
In contemporary Chip-8 interpreters it is customary to store the character set sprites in the first 80 bytes of the memory space that would have originally been occupied by the Chip-8 interpreter, i.e. from address 0x0000. Also, now that memory is not at a premium, the following more regular character set, without any shared data between characters, is often used instead of the original set: