Tandy 1000 Detection -------------------- Ok, first of all, you'll need to detect that you're running on an actual Tandy 1000. The unoffical method of doing this is to check that the byte at F000:FFFE is FFh and the byte at F000:C000 is 21h. function TandyDetected: boolean; begin TandyDetected := (mem[$F000:$FFFE] = $FF) and (mem[$F000:$C000] = $21); end; Tandy Graphics -------------- The Tandy includes all of the extended CGA modes from the PCjr. These are mode 08h: 160x200 with 16 colors, mode 09h: 320x200 with 16 colors, and mode 0Ah: 640x200 with 4 colors. Similar to the CGA modes, all of these have interleaved video memory mapped at segment B800h. NOTE: The 16 color modes on the Tandy/PCjr are NOT split into bitplanes like on the EGA; they are packed pixel modes with the 4-bit colors in the upper and lower nibble of each byte. Sample PutPixel code for each mode is as follows: procedure PutPixel160x200x16(x,y: word; color: byte); var offset: word; begin offset := (y and 1)*8192 + (y shr 1)*80 + x shr 1; if odd(x) then mem[$B800:offset] := mem[$B800:offset] and $F0 + color else mem[$B800:offset] := mem[$B800:offset] and $0F + color shl 4; end; procedure PutPixel320x200x16(x,y: word; color: byte); var offset: word; begin offset := (y and 1)*16384 + (y shr 1)*160 + x shr 1; if odd(x) then mem[$B800:offset] := mem[$B800:offset] and $F0 + color else mem[$B800:offset] := mem[$B800:offset] and $0F + color shl 4; end; procedure PutPixel640x200x4(x,y: word; color: byte); var offset: word; shift: byte; begin offset := (y and 3)*8192 + (y shr 2)*160 + x shr 2; shift := ((x xor 3) and 3) shl 1; mem[$B800:offset] := mem[$B800:offset] and not (3 shl shift) or (color shl shift); end; The Tandy has a limitted palette-setting ability. The color associated with each color number can be chosen from a palette of the 16 possible text colors. You can use video BIOS function 10h, subfunction 0 to set the palette registers, but here are the video ports it sets. procedure SetPalette(reg, color: byte); begin port[$3DA] := 16 + reg; port[$3DE] := color; end; With the CGA modes, the foreground color registers for colors 1, 2, and 3 are 11, 13, and 15, respectively (I have no idea why). So to set color 1 (normally cyan in CGA mode) to dark red (color 4 in text mode), you can do SetPalette(11, 4);. One problem with the Tandy's palette ability, however, is that it is VERY noisy on the screen. Make sure that you wait for a vertical retrace (or at least a horizontal retrace if you optimize enough) before trying to set a palette register or it will cause some definate flicker. One thing that makes the Tandy different from any other IBM compatible computer is that the video memory is actually conventional memory. Tandy's can map any of the last 128k of conventional memory into the video segment B800h. The upper 128k is divided into 8 pages of 16k, numbered 0 to 7. Code to set pages is as follows: procedure SetPages(activepage, displaypage: byte); begin port[$3DF] := activepage*8 + displaypage; end; The active page is the one mapped by the hardware into segment B800h, and the display page is the one drawn on the screen by the video controller. If you are going to use page flipping, make sure you reserve the amount of memory you need (32k-128k) so that none of your data is corrupted. If you want two 16k pages, for example, and you're using a 640k machine (which the compo machine is), make sure that you do not allocate memory for data above segment 9800h, which leaves the 32k required for the video memory. Then you can map page 6 as the active page, which will put it at segment B800h and page 7 at BC00h, and swap the display page between 6 and 7. Note that you'll need to clear any additional pages you want before displaying them because the BIOS will only clear page 7 for you. If you're writing your program on a computer other than a Tandy (which most people don't have access to), it is fairly easy to emulate the palette and page flipping capabilities of the CGA 4-color modes using EGA. Tandy Sound ----------- Tandy's have a sound chip that is capable of producing three voices of square waves. The frequency for each voice can range from 111861 Hz to 109 Hz, and each voice also has a separate volume, ranging from 0 to 15. To program the chip, you send the period, which is 111861/frequency, and the attenuation, which is 15-volume. procedure SetVoice(voice, period, vol: word); begin portw[$C0] := (period shr 4) shl 8 + 128 + voice shl 5 + period and 15; port[$C0] := 144 + voice shl 5 + 15-vol; end; Before sending data to the sound chip, you must enable output by sending the value 68h to port 61h. To turn off a voice, set the attenuation of that channel to 15 (volume 0).