The videoprocessor use in the TI-99/4A comes in three flavors, that differ uniquely by the kind of output signal they send to the monitor port.
The TMS9918A issues a 525-lines, NTSC signal for US television
The TMS9928A issues a 525-line signal, in the form of a B&W luminance/sync signal and two color differential signals. This is meant to drive a RGB monitor, with a minimal external circuitery.
The TMS9929A issues a 625-line signal, in the same format as the 9928A. It is meant for use with the european PAL system.
Whatever its type, the VDP has four display modes: Bitmap (aka Graphic II), Standard (aka Graphic I), Multicolor and Text mode. All modes handle a 256x192 pixels screen in 16 colors except for text mode that handles a 240x192 pixel screen in 2 colors.
The VDP has its own, dedicated memory, that could 4K, 8K or 16K (in the TI-99/4A it's 16K). This memory can be accessed by the CPU, but only through the VDP. The CPU displays objects on screen by placing the appropriate values in the VDP memory.
The VDP contains 8 write-only registers that contains control bits or the memory address of tables used to generate the screen image. It also has a status register that can be read by the CPU.
Bitmap text mode
Bitmap multicolor mode
Colors and gray levels
VDP RAM interface
Monitor interface, TMS9918A
Monitor interface, TMS9928A/9929A
RAS* |1 o 40| XTAL2
CAS* |2 39| XTAL1
AD7 |3 T 38| CPUCLK R-Y on TMS9928A/TMS9929A
AD6 |4 M 37| GROMCLK
AD5 |5 S 36| COMVID Y on TMS9928A/TMS9929A
AD4 |6 35| EXTVDP B-Y on TMS9928A/TMS9929A
AD3 |7 9 34| RESET*/SYNC
AD2 |8 9 33| Vcc
AD1 |9 1 32| RD0
AD0 |10 8 31| RD1
R/W* |11 A 30| RD2
Vss |12 29| RD3
MODE |13 28| RD4
CSW* |14 27| RD5
CSR* |15 26| RD6
INT* |16 25| RD7
CD7 |17 24| CD0
CD6 |18 23| CD1
CD5 |19 22| CD2
CD4 |20 21| CD3
Vcc: +5 Volts
Note: The console power lines +12V, +5V, and -5V are further filtered before being applied to the VDP, RAMs and video circuitery. Possibly to avoid RF interference with the rest of the chips on the motherboard. In addition, the Vcc, Vdd and Vbb pins of each RAM chip are grounded via a dedicated 0.1 nF capacitor. See the oscillator schematic for the by-pass capacitors of the VDP.
CD0-CD7: Cpu data bus. CDO is the most significant bit and is connected to D0 TMS9900 data bus.
MODE: CPU interface mode selection. In the TI-99/4A this pin is driven by the A14 address line (weight >0002).
CSR*: CPU read strobe. The CPU sets this input pin low to read from the VDP. In the TI-99/4A this occurs when accessing even adresses in the range >8800-8BFE.
CSW*: CPU write strobe. The CPU sets this input pin low to write to the VDP. In the Ti-99/4A this occurs when writing to even addresses in the range >8C00-8FFE.
INT*: CPU interrupt output. The VDP uses this output pin to send an interrupt signal to the CPU. If enabled, interrupts are send each time a frame is completed, while the beam is tracing up to the upper left corner of the screen. This occurs about every 1/50th of a second for the TMS9929A and 1/60th of a second for the TMS9918A and TMS9928A. In the TI-99/4A the interrupt is received by the TMS9901 programmable interface system, pin #18 (INT2*).
AD0-AD7: Address/data bus. AD0 is the most significant bit and is connected to DIN on the TMS4116 RAM chip. AD7 is the least significant bit and is connected to A0 on the TMS4116 RAM chip.
RD0-RD7: Read data bus. Each one of these input pins is connected to the DOUT pins of a TMS4116 RAM chip.
R/W*: RAM write strobe. Output pin used by the VDP to indicate read (high) or write (low) memory operations.
CAS*: RAM column address strobe. Output pin used by the VDP to set the memory column address.
RAS*: RAM rwo address strobe. Output pin used by the VDP to set the memory row address.
COMVID: Composite video output. Connected to pin 4 of the monitor port via a complicated amplification circuitery. On the TMS9928A and TMS9929A this pin is the Y signal (black&white luminance and composite sync).
EXTVID: External video input (to combine a signal from another VDP). Connected to pin 5 of the monitor port and grounded via a 560 ohms resistor. On the TMS9928A and TMS9929A this pin is the B-Y color difference output.
CPUCLK: VDP color burst frequency clock.Connected to pin 2 of the monitor port and grounded via a 560 ohms resistor. This signal is also fed to the TMS9919 sound chip (pin 14, CLK) and to the GROMs (pin 13, GRCLK) via a jumper. On the TMS9928A and TMS9929A this pin is the R-Y color difference output.
RESET*/SYNC: This trilevel input pin serves both as a reset signal (when below 0.8V for at least 3 usec) and as a synchronizing input for external video (when above 9V). In the TI-99/4A it is connected to the RESET* output of the TMS9904 clock driver and thus used uniquely as a reset signal. Note that the VDP RAM is not refresh while this line is active and may thus loose data.
XTAL1-2: Connections for an external 10.738635 MHz crystal.
GROMCLK: VDP output clock. This output pin carries a signal that correspods to XTAL/24. It is pulled up to +5V with a 1K resistor and connected to the GROMs (pin 13, GRCLK) via a jumper. According to the VPD used, it is thus possible to select either CPUCLK or GROMCLK as a clock signal for GROMs.
In the TI-99/4A the following circuit is used:
It would also be possible to use an external oscillator, driving two TTL inverters as follow:
+---+ +5V---www---+ +----------+
The first eight registers are used by the CPU to control the VDP. Very unfortunately, these are write-only registers, which means there is no way to determine the current display mode, unless it has been saved somewhere in RAM by the program that set it. Registers 0 and 1 contains control bits, registers 2 to 6 contains pointers to various tables in the VDP RAM and register 7 encodes 2 colors.
The VDP also contains a read-only status register that is uses to pass various information to the CPU.
VDP register 0
This register contains two control bits. All other bits must be zero. The register contains >00 after a reset.
Bit 6 (weight >02) selects a bitmap graphics mode when set to 1. VDP register 1 determines which bitmap mode is used.
Bit 7 (weight >01) enables external video input when set to 1.
VDP register 1
This register contains 7 control bits. All are set as 0 after a reset.
Bit 0 (weight >80) selects the memory size. For 4K of memory the bit is 0, for 16K it is 1.
Bit 1 (weight >40) enables the screen. When this bit is 0 the screen is blank.
Bit 2 (weight >20) enables interrupts. When this bit is 1, the VDP issues interrupt signals on the INT* pin each time it resumes refreshing the screen (vertical retrace signal).
Bit 3 (weight >10) selects text mode when set as 1. Bit 7 of register 0 can be set for bitmap text mode.
Bit 4 (weight >08) selects multicolor mode when set as 1. Bit 7 of register 0 can be set for bitmap multicolor mode.
If both bits 3 and 4 are 0, the display is in standard mode (or in bitmap mode, depending on register 0). Bits 3 and 4 should never be set together.
Bit 5 (weight >04) is reserved and should be 0.
Bit 6 (weight >02) selects the sprite size. When 0, sprites are 8x8 pixels. When 1, sprites are 16x16 pixels.
Bit 7 (weight >01) selects sprite magnification. When this bit is 1, each sprite pixel is replaced by a 2x2 pixels box.
VDP register 2
Defines the location of the screen image table. Only the last 4 bits are used, thus possible values for this register are >00 throught >0F. The value is multiplied by >400 to find the location of the screen image table in the VDP memory. This table contains 1 byte for each character position on the screen (left to right, downwards), this byte contains the character number.
VDP register 3
Defines the location of the color table. Possible values are >00 through >FF and are multiplied by >40 to find the location of the color table. The table is not used in text mode, nor in multicolor mode.
In bitmap mode (i.e. when bit 6 in register 0 is set) the meaning of this register changes: bit 0 (weight >80) is the only one used to determine the address of the color table, which means the table has only two possible locations: >0000 or >2000. The remaining bits are used to define the table size, by the way of an address mask. This is done as follows: the righmost 7 bits are shifted left by 6 positions, filling the rightmost bits with 1s. The result will be a number between >003F and >1FFF, which is ANDed with the address of a character in the table. As a result, the table can have any size between >40 and >2000 bytes (however, note that the maximal usable size is >1800: 3 times >800 bytes).
VDP register 4
Defines the location of the character pattern table. Only the last 3 bits are used, thus possible values are >00 through >07. The value is multiplied by >800 to find the location of the character pattern table. Each entry in the table is eight bytes long and define the pattern of a character, in numeric order. Each byte in an entry defines one line of pixels in the character pattern: bits set as 1 result in foreground color pixels, bits set as 0 encode background color pixels.
In text mode (i.e. when bit 3 in register 1 is set) the last two bits of each byte are ignored since characters are only 6-pixel wide.
In bitmap mode (i.e. when bit 6 in register 0 is set) the structure of this register changes: bit 5 (weight >04) is the only one used to determine the address of the color table, which means the table has only two possible locations: >0000 or >2000. The two rightmost bits are used to determine the length of the table, by the way of an address mask. This is done by shifting them 11 positions to the left, filling the righmost bits with 1s. The result will be a number between >07FF and >1FFF that will be used as an address mask. At least, this is what happens in bitmap + text mode (i.e. when bit 3 of register 1 is set). In standard bitmap mode, the righmost bits are not necessarily 1: they are taken from VDP register 3, i.e. the address mask of the color table is used for both the color table and the pattern table addressing.
VDP register 5
Defines the location of the sprite attributes table. Only the last 7 bits are used, thus possible values are >00 through >7F. The value is multiplied by >80 to find the location of the sprite attributes table. Each entry in the table is four bytes long and defines a sprite position and color, in numerical order of sprites. See the chapter on sprites for a detailed description of this table.
VDP register 6
Defines the location of the sprite pattern table. Only the last 3 bits are used, thus possible values are >00 through >07. The value is multiplied by >800 to find the location of the sprite pattern table. Each entry in the table is eight bytes long and defines the pattern of a sprite, one byte per line. Bits that are set as 1 result on a pixel of the color defined for that sprite in the sprite attributes table, bits that are 0 result in a transparent pixel. If the large sprite size is selected (bit 6 in register 1 is set as 1) each entry is 32 bytes long and define a sprite as a set of 4 characters arranged as:
VDP register 7
The first nibble of this register defines the color of all characters in text mode. It is not used in the other modes.
The second nibble defines the background color wich is used for all characters in text mode. In all four modes it defines the color of the backdrop plane: this is the color of the screen outside the display area and the color that appears under transparents characters. When this color is set as transparent the external video image appears if it is enabled, black color appears otherwise.
The first 3 bits of this register are automatically reset as 0 when the register is read or when the VDP is reset. It ensues that the status register should only be read when an interrupt is pending, otherwise an interrupt could be missed.
Bit 0 (weight >80). This bit is set to 1 at the end of the
raster scan of the last line of the display area (i.e. before drawing
bottom margin). If interrupts are enabled (by bit 2 in VDP register 1),
the INT* pin is low when this bit is 1 and high when it's 0. This is
the status register should be read after each frame, in order to clear
the interrupt and be ready to receive the interrupt at the end of the
frame. Also, if bit 2 in VR1 is cleared and set again while status bit
0 is set, an interrupt is issued immediately.
Bit 1 (weight >40) signals that there are 5 or more sprites on a given pixel row. Only the topmost four will be displayed.
Bit 1 (weight >20) is the coincidence bit. It is set when two sprites or more have at least one overlapping "on" pixel. This occurs even if the sprite color is transparent. Note that coincidence is checked only every 1/60th of second (1/50th of a second for the TMS9929A), thus if you change sprite positions during that time a coincidence could be missed.
Bits 3 to 7 contain the number of the 5th sprite on a pixel line, if any. This number is only meaningfull if bit 2 is set as 1 (else it may contain the number of the last displayed sprite, but no guaranty). If such a situation occurs more than once, the 5th sprite listed is the one closest to the top of the screen.
Summary of the VDP registers contents
|VR1||16K||Blank||Int on||Multic||Text||0||Size 4||Mag 2x|
|0||0||0||0||0||Char pattern table|
|VR5||0||Sprite attributs table|
|VR6||0||0||0||0||0||Sprites pattern table|
|VR7||Text color (in text mode)||Backdrop color|
|Status||Int||5+ sp||Coinc||5th sprite number|
This mode is selected by setting all mode bits as 0: bit 7 in register 0 and bits 3 and 4 in register 1. VR0: 0 VR1: 0 0
In this mode, the screen is divided into 24 rows of 32 characters. Each character is 8x8 pixels and has two colors: one for the "on" pixels (foreground color), one for the "off" pixels (background color). If a color is set as 0, the color of the backplane will be used (defined by register 7).
The screen image table is thus >300 bytes long (24x32=768). Each byte in the table contains the number of the character to display at the corresponding position on screen. This number is used to locate the character pattern in the pattern table and to look up its colors in the color table.
The color table is 32 bytes long. Each byte encodes the two colors for a group of 8 consecutive characters in numeric order (i.e. the first byte affects characters 0-7, the second characters 8-15, etc). In each byte, the first nibble encodes the foreground color, the second nibble the background color.
The character pattern table contains 256 entries, one per character in numeric order. Each entry is eight bytes long, each byte defines the pattern of one pixel row in the character: "1" bits set the pixel to the foreground color used for this character group, "0" bits set the pixel to the background color of this character group.
| | 00000000 = >00
| *** | 00111000 = >38
| * * | 01000100 = >42
| * * | 01000100 = >42
| *** | 00111000 = >38
| * | 00010000 = >10
| *** | 00111000 = >38
| * | 00010000 = >10
The pattern table entry for the above character would be: >00 38 42 42 38 10 38 10
Sprites can be used in standard mode, see below.
This mode is selected by setting bit 3 of VDP register 1 as 1. Bit 4 must be 0, as well as bit 7 of register 0. VR0: 0 VR1: 1 0
In this mode, the screen is devided into 24 rows of 40 characters. Each character is made of 8 rows of 6 pixels. All characters have the same two colors, defined by VDP register 7.
The screen image table is >3C0 bytes long (24x40=960).Each byte in the table contains the number of the character to display at the corresponding position on screen. This number is used to fetch the character pattern from the pattern table.
The color table is not used. The foreground color for each character is taken from the first nibble of VDP register 7, the background color is transparent, which lets the backdrop plane color appears. As the backdrop color is encoded by the second nibble of VDP register 7, one can consider that this register specifies both the foreground and background colors for each character.
The pattern table is organized just as in standard mode, except that the last two bits of each byte are ignored since characters are only 6-pixels wide in text mode.
| | 000000xx = >00
| *** | 001110xx = >38
| * *| 010001xx = >42
| * *| 010001xx = >42
| *** | 001110xx = >38
| * | 000100xx = >10
| *** | 001110xx = >38
| * | 000100xx = >10
Sprites are not available in text mode.
All this makes text mode the least memory-hungry mode: only a maximum of 3008 bytes (>0BC0) of VDP RAM is required in this mode. This can be further reduced by not using all 256 characters and/or by partly overlapping the tables.
This mode is selected by setting bit 4 of VDP register 1 as 1. Bit 3 must be 0, as well as bit 7 of register 0. VR0: 0 VR1: 0 1
In this mode, the screen is divided into 48 rows of 64 boxes. Each
is 4x4 pixel and can be independently assigned a color. The screen
table is still >300 bytes long, but each byte now represent a
made of 4 boxes. The boxes are arranged as:
The color of the boxes are defined in the character pattern table
Each entry in the table is 8 bytes long but only 2 bytes are used to
the colors of the 4 boxes that make up a character: >01 >23. To
wasting 6 bytes in each entries, the characters on 4 consecutive rows
the same entry, with an offset of 2 bytes:
characters on row 0, 4, 8, 12, 16 and 20 use bytes 0 and 1,
characters on row 1, 5, 9, 13, 17 and 21 used bytes 2 and 3,
characters on row 2, 6, 10, 14, 18 and 22 used bytes 4 and 5,
characters on rows 3, 7, 11, 15, 19 and 23 use bytes 6 and 7.
This reduces the size of this table to 1536 bytes (24 rows x 32 columns x 8 bytes).
The color table is not used in multicolor mode.
Sprites can be used in this mode.
To summarize, the screen organisation is the following:
Column: 0 1 ... 31
Row 0: a b q r ...
c d s t
Row 1: e f u v
g h w x
Row 2: i j y z
k l ...
Row 3: m n
The corresponding screen image table could be:
Column: 0 1 ... 31
Row 0: >00 >01 ... >1F
Row 1: >00 >01 >1F
Row 2: >00 >01 >1F
Row 3: >00 >01 >1F
Row 4: >20 >21 >3F
And the pattern table would look like this (letters a-z represent the color of a given box, i.e. a digit in the range >0-F):
Byte: 0 1 2 3 4 5 6 7
Row: 0 1 2 3___
Entry >00: >ab >cd >ef >gh >ij >kl >mn >op
Entry >01: >qr >st >uv >wx >yz ...
This mode is fairly complicated to use (and does not yield very interesting results). A way to simplify it is to fill the screen with fixed character numbers, as shown in the above example. Drawing is then achieved by changing the color values in the character pattern table. Arranging the character numbers as in the example makes easier to calculate which byte must be changed in the pattern table, but there are other solutions.
I'm sure every TI user had this great idea one day or the other: "Hey, lets fill the screen with all available characters: 0, 1, 2, etc. Then I can draw pixel-by-pixel by just changing definitions in the character pattern table". If you have tried, you must have realised there is a big problem: with 256 characters, we can only cover 1/3 of the screen. Not to mention the fact that the color table defines 8 characters at a time, which makes color drawings almost impossible. Bitmap mode takes care of these problems (sort of).
This mode is selected by setting bit 7 of register 0 as 1. Bits 3 and 4 in register 1 should be 0. VR0: 1 VR1: 0 0
In this mode, the screen is still devided in 24 row of 32 character, just as in standard mode. However, we now have three character pattern tables, one after the other: the first table applies to characters displayed in the top third of the screen (i.e. the first >100 bytes in the screen image table), the second to characters displayed in the middle third (bytes >100-1FF) and the third to characters displayed in the bottom third of the screen (bytes >200-2FF in the screen image table).
Now we can fully cover the screen with non-redundent characters, by just writing >00, >01, >02 ... >FF three times in the screen image table. As the three pattern tables are consecutive, it is easy to calculate which byte is to be accessed to modify a given pixel.
There are also three color tables, arranged in the same way as pattern tables. Each entry in a table is eight bytes long and defines the colors for one character. Each byte in an entry defines the colors of a row in the character: the first nibble sets the pixel color for bits that are set as 1 in the pattern (foreground), the second sets the pixel color for the 0 bits in the pattern (background). The major drawback of this system is that each line of pixels in the display is chopped into 8-pixels clusters for which there is only a choice of two colors. This forces us to pay a lot of attention when drawing complex images, as 3 colors in a given pixel line must be at least 8 pixels appart.
Sprites are available in bitmap mode and work just as in standard mode.
Not so surprisingly, bitmap mode is extremely memory-hungry: it requires >3300 bytes, not counting sprite tables.
To summarize, here is an example showing the correspondance between screen, pattern table entry and color table entry:
Screen Pattern table Color table
B 1 B B B B B 1 0 1 0 0 0 0 0 1 1 (black) B (l.yellow)
B B 7 B B B 7 B 0 0 1 0 0 0 1 0 7 (cyan) B
B B B C B C B B 0 0 0 1 0 1 0 0 C (green) B
B B B B E B B B 0 0 0 0 1 0 0 0 E (gray) B
B B B B 8 B B B 0 0 0 0 1 0 0 0 8 (m.red) B
B B B B 5 B B B 0 0 0 0 1 0 0 0 5 (l.blue) B
B B B B 6 B B B 0 0 0 0 1 0 0 0 6 (d.red) B
2 2 2 2 D 2 2 2 0 0 0 0 1 0 0 0 D (magenta)2 (m.green)
The VDP register setting could be the following:
VR0 >02 Bitmap mode on
VR1 >C0 16K, screen on
VR2 >08 Screen image at >1800 (we can't have it at >0000 since either the pattern or the color table must be there)
VR3 >FF Color table at >2000, address mask = >1FFF (full size table: 3 times >800 bytes)
VR4 >03 Pattern table at >0000, address mask = >1FFF (full size table: 3 times >800 bytes)
Note that the trick of covering the screen with three repeats of characters 0-255 is just an easy way to calculate which byte corresponds to which pixel, this is by no means an obligation. You could use the tables just the way you do in standard mode: having fixed pattern definitions (and colors) and placing a character number in the screen image table to display it. The address masking trick becomes very handy in this case. Rather than having three copies of the pattern table one after the other, let's just have one and set the address mask to 0: in the example above, VR4 would become >00. The advantage over standard mode is that we can set different colors for each character (rather than for a group of 8). In fact, we can even set a color pair for each pixel row in a character: this is a nice way to create iridescent characters!
Finally, both solutions can be mixed in the various thirds of the screen: the top two thirds could be arranged for easy bitmap drawing, whereas the bottom third could be arranged for rapid character writing. Some games use this solution to display prompts and scores at the bottom (or top) of the game screen.
You can use the mask bits in register 4 to assign a >800-byte
table to each third of the screen:
>00 (or >04): only one pattern table, identical for each third of the screen.
>01 (or >05): two pattern tables. One at >0000 (or >2000) for the 1rst and 3rd thirds, one at >0800 (or >2800) for the middle third of the screen.
>02 (or >06): two pattern tables. One at >0000 (or >2000) for the 1rst and 2nd thirds, one at >1000 (or >3000) for the bottom third of the sceen.
>03 (or >07): three pattern tables. One at >0000 (or >2000) for the 1rst third, one at >0800 (or >2800) for the 2nd third and one at >1000 (or >3000) for the bottom third of the screen.
Then we could do the same for the color table, using bits 1 and 2 (weight >40 and >20) to select the number of tables. The remaining bits will affect character grouping within a table. Since they also affect grouping whitin the pattern table, we'd better be carefull with these!
In summary, these would be the addresses of the tables in 8 possible situations:
|VR3||VR4||Mask||Top 3rd||Middle 3rd||Bottom 3rd|
To group characters within a table, we could further alter the color table mask:
The table below lists the six most logical values, plus two gooffy ones (just for fun).
|>1F||>07FF||Each char is unique||256||1|
This is the mode TI forgot to tell us about. It works just like standard bitmap mode, except that the screen is now 40 columns and that only two colors are available.
This mode is selected by setting bit 7 of register 0 as 1. Bit 4 in register 1 should be 1. VR0: 1 VR1: 0 1
The screen is now divided in three, each third is 8 lines high and thus occupies >140 bytes in the screen image table (8*40=320).
The colors are taken from VR7, just like in regular text mode. There is no color table, and the contents of VR3 is irrelevant.
Just like in standard bitmap mode, there can be upto 3 pattern
located either at >0000 or at >2000. You can use the address mask
bits in VR4 to determine which third of the screen uses which table.
main difference is that the color address mask is not used to fill-in
patten address mask: >07FF is always used instead. No character
to worry about, then! This mode comes handy for black-and-white
Another undocumented mode. It works as a mixture of bitmap and multicolor mode.
This mode is selected by setting bit 7 of register 0 as 1. Bit 3 in register 1 should be 1. VR0: 1 VR1: 1 0
The screen is now divided in three, each third is 8 lines high and thus occupies >100 bytes in the screen image table (8*32=256).
Just like in standard multicolor mode, there is no color table and the contents of VR3 is irrelevant.
The color of the boxes are taken from upto 3 pattern tables, located either at >0000 or at >2000. You can use the address mask bits in VR4 to determine which third of the screen uses which table. Since a single table would be sufficient for this purpose, there is no real point in using this combined mode...
It is not allowed to set text and multicolor mode together, whether in bitmap mode or not. VR0: x VR1: 1 1
If you try, the VDP will display a fixed image, that is not
by the contents of the VDP memory, nor by registers VR2 to VR6 (sprites
are not available). The screen is 192 pixel lines and 40 columns. Each
column is made of 4 pixels in foreground color, followed by 2 pixels in
backgroud color. These two colors are taken from VR7.
Sprites are special characters that can be displayed at any position on screen, i.e they are not limited to a grid or rows/column, instead each sprite position can be defined with a precision of one pixel.
Sprites can be either 8x8 pixels or 16x16 pixels depending on the setting of bit 6 in VDP register 1: when this bit is 0 all sprites are 8x8, when it is 1 all sprites are 16x16. In addition, bit 7 in VDP register 1 provides a mgnification feature: when this bit is 1 all sprites are magnified by a factor of two. Concretely this means that each "pixel" becomes a 2x2 pixels box.
Each sprite can have its own foreground color. The background color is always transparent, which lets the underlying image appear under the sprite.
Upto 32 sprites can be displayed at a time. Each one can be seen as
an extra image plane on the top of the screen, overlapping each others,
with sprite number 0 at the top. Thus the virtual image planes are:
- External video
- Backdrop plane (color in VDP reg 7)
- Image plane (characters)
- Sprite number 31
- Sprite number 30
- etc upto:
- Sprite number 0
There is one restriction however: the VDP cannot display more than 4 sprites on a given line of pixels. Thus, if 5 sprites or more must be drawn on the same line, only the topmost four (those with the smallest numbers) can be displayed. The number of the 5th one is placed in the status register together with a flag bit and the others are ignored. This occurs whether or not the sprites are actually overlapping: one could be on the left of the screen, the other on the right with the same result.
Coincidence is a different condition: whenever two "on" pixels in different sprites occupy the same screen location, a bit is set in the VDP status register. This comes handy for games programming: an easy way to check whether the bullet hits the target. Note however that the VDP does not tell you which are the overlapping sprites...
Sprites characteristics are defined in two tables pointed by VDP registers 5 and 6: the sprite attributes table and the sprite patterns table.
This table is pointed at by VDP register 6. It contains upto 32 entries for the 32 sprites arranged in numeric order. Each entry is four bytes long, thus the maximum size for this table is >100 bytes. The four bytes define sprite characteristics as follows:
|Byte 1||Byte 2||Byte 3||Byte 4|
|Sprite 0||vertical position -1||horizontal position||pattern number||clock bit||sprite color|
Sprite positions are expressed in pixels relative to the top left corner of the display area. This will be the position of the top leftmost pixel of the sprite (unless the early clock bit is set, see below). Note that the vertical position coordinate in the table is offset by one: therefore the topmost pixel line is >FF, the second is >00, the third is >01 and the last is >BE. Any sprite whose vertical position is greater than >BE won't be visible on screen, although coordinates close to >FF can result in the bottom of the sprite appearing at the top of the screen. Similarly, row values just under >BE result in partly blending off the bottom of the sprite.
The same thing is true for sprite approaching the right border of the screen (horizontal coordinates close to >FF): the sprite appears to blend-in from the right. However this won't work on the left of the screen: when the horizontal position is 0 the whole sprite is visible, when it's lower than 0 (i.e. >FF, >FE, etc), the sprite appears at the right of the screen. To allow for sprite blend-in from the left of the screen one can set the "early clock" bit (bit 0, value >80) in the color byte: the horizontal coordinate now refers to a point located 32 pixels to the right of the upper left corner of the sprite. This results in shifting the sprite 32 pixels to the left and allows for partial disappearance on the left side (but not any more on the right).
The pattern number refers to the entry containing the sprite pattern in the sprite pattern table.
Finally the sprite color is defined by the right nibble in the byte 4 of the entry.
The sprite attributes table does not need to define all sprites: if the vertical position of a sprite is set as >D0, the sprite won't be displayed (as it's off-screen), but neither will any of the following sprites. This comes handy to quickly erase all sprites by just changing one byte in the attributes table.
This table contains patterns to be used by the various sprites, arranged in ascending order. Each entry is either 8 bytes long or 32 bytes long depending on the sprite size.
If the sprite size is set as 8x8, entries are 8 bytes long. Each byte defines a row in the sprite: "1" bits result in pixels of the color specified for that sprite in the attributes table, "0" bits encode transparent pixels and are ignored for display purposes.
If the sprite size is set as 16x16 (VDP register 1, bit 6 set as 1)
each entry is 32 bytes long. These bytes define the sprite pattern as
it were made of four "normal sprites" arranged in a 2x2 formation:
Thus, bytes 0-7 define the top left quadrant, one byte per line of 8 pixels. Bytes 8-15 define the bottom left quadrant in a similar fashion. Bytes 16-23 define the top right quadrant, one byte per line of 8 pixels (which now corresponds to pixels 9-15 of the sprite rows 0-7) and bytes 17-23 define the lower right quadrant.
Even wiith a 16x16 pixels size, 32 sprites require at most >400 bytes (32x32). Thus there is room enough for extra sprite patterns and a sprite can be animated by quickly changing its pattern number in the attributes table rather than by modifying the sprite pattern table.
The VDP could use several types of DRAM chips: 4027-type (4 Kbits), 4108-type (8 Kbits) or 4116-type (16 Kbits). In the TI-99/4A console, there are 8 TMS4116 RAM chips, installed as shown below. They make up for 16 Kbytes of VDP memory.
These RAMs are organised as a matrix of bits: the TMS4116 has 128 row x 128 columns. The VDP uses 3 command lines to control the RAMs: to select a row, it places the row number on AD0-AD7 (AD0 is always 0) and pulses the RAS* line low so that the RAM can latch the address. Similarly, the CAS* line is used to select a column number. Once the address of a bit has been set the each RAM will issue the corresponding bit on its DOUT pin. If it is a read operation, the VDP can just access the data on pins RD0-RD7. For write operations, the VDP can write bits to the selected address by pulsing the R/W* line low: each RAM chip will store one bit at the selected coordinates.
In between operations, the VDP refreshes the RAMs by systematically selecting each row and activating the RAS* line. This is necessary since DRAMs will "forget" data if they are not read periodically. This normally requires a special refreshig circuit, but in our case the VDP takes care it.
This fairly complicated table is an attempt to explain how the VDP generates the 14-bit RAM addresses, according to the video mode and the table to be accessed.
|Video mode||Table accessed||A0||A1||A2||A3||A4||A5||A6||A7||A8||A9||A10||A11||A12||A13|
|Standard||Screen image||VR2, bits 4-7||Row (0 to 23)||Column (0 to 32)|
|Color||VR3, bits 0-7||0||Char #, bits 0-4|
|Char pats||VR4, bits 5-7||Char #||Char pat row|
|Text||Screen image||VR2, bits 4-7||Text position: (Row * 40) + Column|
|Char pats||VR4, bits 5-7||Char #||Char pat row|
|Multicolor||Screen image||VR2, bits 4-7||Row||Column|
|Char pats||VR4, bits 5-7||Char #||Square row, 5-7|
|Bitmap||Screen image||VR2, bits 4-7||Row||Column|
|Color||VR3, 0||3rd||Char #||Char pat row|
|Char pats||VR4, 5||3rd||Char #||Char pat row|
|Sprites||Attributes||VR5, bits 1-7||Sprite #||Param|
||Size 1||VR6, bits 5-7||Sprite #||Sprite pat row|
|Size 4||VR6, bits 5-7||Sprite #, bits 0-5||Quadrant||Sprite pat row|
VRx: VDP register x. The least significant bits are used, except in bitmap mode (MSB = >2000, others = mask).
3rd: Third of the screen. 0=upper, 1=middle, 2=lower (3 never occurs).
Param: 0=pixel row-1, 1=pixel column, 2=Pat #, 3=color (+clock bit)
Quadrant: 0=upper left, 1=lower left, 2=upper right, 3=lower right (8x8 pixels each)
In bitmap mode, the resulting address for the color and char pats tables is ANDed with an address mask. See the discussion of bitmap mode for details.
The TMS9900 CPU communicates with the VDP via an 8-bit data bus and three control lines.
The CSR* line signals a read operation and instructs the VDP to place a byte on the data bus. According to the value of the MODE line, this byte can be the content of the status register (MODE is high) or a byte transfered from the VDP RAM (MODE is low). Reading the status register resets its content, readind a byte from the RAM increments the internal address pointer in the VDP, so that the next operation will return the next byte in RAM.
The CSW* line signals a write operation and instructs the VDP to latch the byte currently on the data bus. The MODE line is used to differentiate data bytes (MODE is low) from command bytes (MODE is high). Writing a byte to the RAM increments the address pointer in the VDP, so that the next byte will be written to the next address in RAM. Command bytes are always passed as a pair, the two most significant bits of the second byte indicates the type of command: >80 to write to a VDP register, >40 to set the address for a RAM write operation, and >00 to set the address for a RAM read operation. If the first byte was sent by mistake, one can cancel it by reading the status register.
In the TI-99/4A the MODE line is connected to address line A14 (weight >0002). CSR* is triggered by any operation with even addresses in the range >8800-8BFE, whereas CSW* is activated by a write operation to an even address in the range >8C00-8FFE. Traditionally, the following four ports are used to communicate with the VDP:
>8800 Read next byte from the VDP RAM and increment the address
>8802 Read the status byte from the status register, resets it, and clear interrupt.
>8C00 Write a byte to the next address in the VDP RAM and increment the address pointer.
>8C02 Send a command byte to the VDP (commands must be a pair of bytes).
The three possible commands are the following:
|Command||First byte||Second byte|
|Write to register||Reg content||1 0 Reg#|
|Set address for write||A6-A13||0 1 A0-A5|
|Set address for read||A6-A13||0 0 A0-A5|
You will have noticed that commands are 2-byte long. The VDP maintains an internal flag to know whether the first byte has already arrived. Once the second byte arrives, the command is executed. It is of importance to realize than any access to the data port (>8800 or >8C00) or to the status port (>8802) will reset this flag. This was probably done so that you can put the VDP in a known state in case something went wrong with programming: otherwise the only way to reset the byte flag would be a hardware reset! This is why interrupt must be disabled during VDP operations: since the interrupt service routine accesses the VDP it would cancel any pending command if an interrupt occured in-between the two bytes.
The VDP maintains only one internal address pointer, for both reading and writing. You could thus wonder why we must tell the VDP whether we are setting the address for a read or a write operation. This is because the chip contains a 1-byte read-ahead buffer. As soon as the address is set for a reading operation, the VDP gets the relevant byte from the RAM and stores it in the read-ahead buffer. It then increments the reading pointer. This way, when the CPU finally asks for the byte value (from port >8800), the VDP can provide it immediately. It then fetches the next byte and has it ready for the next CPU request. This read-ahead strategy considerably speeds up reading operations.
By contrast, when the CPU sets an address to write, all the VDP does is to update its internal address pointer. When the CPU provides the new byte value (at port >8C00), the VDP places it in the RAM and increments the address pointer.
The VDP needs 2 microseconds to read or write a byte to its RAM. In addition, it can only communicate with the CPU at precise moments, when it is not too busy with building the screen. Such moments are known as CPU access windows and may arise at various intervals depending on the video mode. In standard or bitmap mode, a window occurs every 16 memory cycles, each cycle being 372 ns long. This means the VDP may have to wait upto 5.95 us before a CPU access window occurs. Adding the 2 us needed for RAM access gives us a maximum delay time of 8 us. Of course, it can be as fast as 2 us if a window just happens to open (even less for reading operations, thanks to the read-ahead buffer). In text mode, a window opens every three memory cycles, i.e. at intervals of 1.1 us. In multicolor mode, a window opens every four memory cycles, i.e. at 1.5 us intervals.
There are two exceptions to these rules, however:
for a window
|2 us||0 - 5.95 us||2 - 8 us|
|Building screen||Text||2 us||0 - 1.1 us||2 - 3.1 us|
|Building screen||Multicolor||2 us||0 - 1.5 us||2 - 3.5 us|
|Vertical retrace||Any||2 us||0||2 us|
|Blank screen||Any||2 us||0||2 us|
Contrarily to standard memory, the VDP cannot hold the CPU in a wait state until it is ready to accept/send data. This means that the application program must contain appropriate delays to prevent the CPU from going on with the next operation before the VDP has completed the current one. A typical example is passing the two command bytes to the VDP: using two successive MOV instructions is too fast and the second byte won't be read. The program should thus contain another instruction in between the two MOV (such as a NOP or a SWPB).
Looking into the cable (invert left + right for console socket)
European consoles (TMS9929A VDP)
3 Sound output
US consoles (TMS9918A VDP)
4 Composite video
5 Signal ground
The composite video signal from the TMS9918A can drive a color monitor. It incorporates chrominance, luminance and all necessary vertical and horizontal synchronisation. The output buffer for the COMVID pin is a source-follower MOS transistor internally connected to Vcc, which requires and external pull-down resistor (typically 330 Ohm to provide a 1.9V sync level). This load resistor determines the sharpness of the edges on the video signals: lower resistance provides faster fall times and a sharper picture. While the VDP signals are not exactly equivalent to the NTSC colors, the difference can be easily corrected with the color and tint controls of the monitor (direct quote from the TI doc).
The Y, R-Y and B-Y video signals from the TMS9928A and TMS9929A require an external encoding circuitery to drive a RGB monitor. The Y output signal incorporates the luminance signal and the necessary synchronisation signals. R-Y (red minus Y) and B-Y (blue minus Y) contain unmodulated chrominance information and are used in NTSC and PAL systems to modulate two carriers in quadrature. The output buffers are identical to the COMVID buffer described above and require the same pull-down resistor.
For the TMS9918A, this results in the following hierarchy of gray levels. These levels differ slightly on the TMS9928A and TMS9929A.
4 D. blue
6 C D.red, D.green
2 5 8 D M.green, L.blue, M.red, Magenta
3 9 L.green, L.red
7 A Cyan, D.yellow
B E L.yellow, Gray
The 10.738635 oscillator is used to derive a six-phase internal clock signal at 3.579545 MHz to provide the video color signal and the color burst signal used by the TMS9918A. The master clock signal is divided by two to provide the pixel clock (5.3 MHz), by three to provide CPUCLK (3.58 MHz for the TMS9918A only) and by 24 to provide GROMCLK (3.58 MHz for the TMS9928A only).
The pixel clock drive an horizontal pixel counter that in turn drives a vertical line counter. These counters are used to generate the synchronisation signals incorporated in COMVID or Y. The TMS9918A and the TMS9928A operate at 262 lines per frame and approximately 60 frames per second in non-interlaced mode. The TMS9929A operates at 313 lines per frame and approximately 50 frames per second.
|Horizontal||Pixel clock cycles|
|Text mode||Other modes|
With CL= 300 pF. All units are nanoseconds (ns) i.e. 10-9
Fcpuclk = 3.4 (min), 3.58(typ), 3.76(max) MHz
Fgromclk= 425.12(min), 447.5(typ), 469.88(max) MHz
__________| 200 ns |
| 30 || 30 | | |
XX valid address XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX MODE
| 100 | |30 |
XXXXXXXXXXXXXXXXXXXXXXXXXX valid data XXXXXXXX CD0-CD7
| 0 |
XX valid address XXXXXXXXXXXXXXXX MODE
| 100-150 | | 0 |65-100 |
-------------------< valid data XXXXXXXX>--- CD0-CD7
With CL= 50 pF. All units are nanoseconds (ns) i.e. 10-9 second.
| >372 ns |
\ 190-230 ns /|100-150 \ RAS*
| 30-50 | 150-190 ns | |
| | | >45 (65) |
| \| 220-250 ns /| 80-120 ns \_ CAS*
| 95-125 ns | | |
| 95-130 ns | | | |
|-10 to -2| | 240-280 ns | | |
|25-65|20-30| | | 45-85 | | | |
XX row XXXX column XX data XXXXXXXXXXXXXXXXXXXXXX AD0-AD7
| | |135-195| | |
| | | 140-160 | |
| |a|| 60-90 ns |
| \| 170-210 / 25-75 \ R/W*
| 200-310 ns |
a) 0-20 ns
| >372 ns |
\ 190-230 ns /100-150\ RAS*
| 30-50 | | >45 (65) |
| \ 220-250 ns / 80-120 ns \_ CAS*
| 95-130 ns | |
|26-65|20-30| |a |45-85 | |
XX row XXX column XXXXXXXXXXXXXXXXXXXXXXXXXXXXX AD0-AD7
XXXXXXXXXXXX/ | \XXXXXXXXXXXXX R/W*
| >60 |>0|
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX data XXXXXXXXXXXXXX RD0-RD7
a) -10 to -2 ns
42-47-52 2.75 V
/ \ / \ XTAL1
/ \ 42-47-52 / \ 0.8 V
| | | | |
x-10-15 | 42-47-52 | x-10-15
\ / \ /
\ / \ / XTAL2
Values given for frequencies: 10.738098 MHz (min)
10.738635 MHz (nom)
10.739172 MHz (max)
With RL = 470 Ohm and CL= 150 pF
Units are nanoseconds (ns, 10-9 sec), microseconds (us, 10-6 sec) and milliseconds (ms, 10-3 sec)
Vwhite 2.72 us 2.79 us
/ \ ,~~~, / \
___ 372ns 1.49us/ \ ,~~~' `~~~, / \
Vcb Vblack ----, ,--/\/\/\/\---' `--' `~~~' \______
Vsync \4.4 us/ 261 us | | | | 47.68 us | | | |1.49us\____
10ns 20ns 60ns 110ns 60ns 110ns
Horiz Color Left | Active display | Right Horiz
sync burst border | area | border sync
__ __ __ __ __ __ __ __ _ _ _ _ __ __ __ __ _ _
\/ \/ \/ \/ \/ \/\_ ________/ \/ \/ \/ \/ \/ \/
242 243 244 245 246 247 249 250 251 262 1 2 3
End bottom | Vertical | Vertical | Vertical back | Start top
border | front | sync | blanking * | border
| blanking*| | |
---------->| 191.1 us | 191.1 us | 828 us |<--- 18.8 msec --
* Color burst output suppressed
With RL = 470 Ohm and CL= 15 pF
| Horizontal line: 63.695 usec |
One pixel __ Vwhite
186.24ns / \
______/ \ / \ ______
___ _______/2.8us \___/ \___/2.42us\______ Vblack
|| || | | | |
110ns 150ns 75ns 50ns
Horiz Back Left | Active display | Right Front Horiz
sync porch border| area | border porch sync
/ \ ___
Vcb _____ / \ / \
Vno_color ____/2.6us\______ / \ / \ __
|| ||1.49us\_____/ \ _ _ _/ \_____/
Vblack 150ns 100ns 2.8us \____/ 2.4us
Color Left | Active display area | Right
burst* border 47.67 usec border
* For TMS9929A only
/ \_ _ _ ___
Vno_color ____ ______ / \ _____/
\ /1.49us\_____ / \ /2.4us
Vneg_cb \2.6us/ 2.8us\ / \____/
Vblack | | | | \___/
Vsync 100ns 150ns
Color Left | Active display area | Right
burst* border 47.67 usec border
* For TMS9929A only
__ __ __ __ __ __ 465ns __ __ _ _ _ _ __ __ __ __ _ _
\/ \/ \/ \/ \/ \/\__________/ \/ \/ \/ \/ \/ \/
292 293 294 295 296 297 298 300 301 302 313 1 2 3
End bottom | Vertical | Vertical | Vertical back | Start top
border | front | sync * | blanking * | border
| blanking*| | |
---------->| 191.09 us| 191.09 us | 828.04 us |<--- 18.7 msec --
Vertical time: 19.91 msec
* Color burst output suppressed
Supply voltage, Vcc............................-0.3 to 20 V
All input voltages................................-0.3 to 20 V
Output voltage....................................-2 to 7V
Continuous power dissipation..............1.3 W
Operating free-air temperature.............0 to 70 `C
Storage temperature range..................-55 to 150 `C
|Supply voltage, Vcc||4.75||-||5.25||V|
|Supply voltage, Vss||-||0||-||V|
|Input voltage on
|Input voltage on
EXT VDP pin
|Low level input voltage||-||-||0.8||V|
|Operating free-air temperature||0||-||70||`C|
|RAS*, CAS*, R/W*||I=400 uA||2.7||3.4||-||V|
|All other outputs||2.4||3.2||-||V|
|CPU data||I=1.2 mA||-||0.3||0.6||V|
|DRAM interface||I=0.8 mA||-||-||0.6||V|
|Off-state output current, D0-D7 high||V=5.25 V||-||1||100||uA|
|Off-state output current, D0-D7 low||V=0.4V||-||-||-100||uA|
|High-level input current||V=5.25 V||-||-||10||uA|
|Low-level input current||V=0 V||-||-||-10||uA|
|Video voltage difference, white-black
Y, R-Y, B-Y outputs
|Average supply current from Vcc||Temp=25 `C||-||200||250||mA|
other pins at 0V
|All other inputs||-||-||10||pF|
|Video voltage level of white on COMVID||R = 470 Ohm||2.8||3.0||3.2||V|
|Video voltage level of black on COMVID||2.1||2.3||2.5||V|
|Video voltage level of sync on COMVID||1.85||2.0||2.1||V|
|Video voltage level of white on Y, R-Y, B-Y||R = 470 Ohm||2.5||3.0||3.6||V|
|Video voltage level of black on Y, R-Y, B-Y||1.6||2.3||2.5||V|
|Video voltage level of sync on Y, R-Y, B-Y||1.2||1.8||2.0||V|
|Color burst video voltage level with
respect to voltage when no color
Back to the TI-99/4A Tech Pages