|DÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ |Dº |5The Happy Hacker |DºÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ |DÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ^C^1A VIDEO TUTORIAL -- Part 7 ^Cby Joel Ellis Rea ^CBIOS Video Services In the past two issues we discussed how to access features of the MDA and CGA by directly manipulating both their own ports and the registers on the Motorola 6845 CRTC chip. Such direct access is the fastest way to operate these, or any other, video boards. However, they are not very standard, since other systems which have similar operating systems and video display capabilities (the PCjr, for example) may not have the same physical hardware in the same addresses. So direct access requires specific or very compatible hardware. The designers of the IBM PC recognized that this might cause problems, and also that a programmer who simply wanted to initialize an 80-column by 25 row text display might not want to have to set a bunch of CRTC registers and video adapter ports manually. For such video accesses, and many other things such as low-level floppy disk control, printer access, etc., the designers provided a special program called the Basic Input/Output Services program, or BIOS, which resides in a special ROM chip on the motherboard of every IBM computer or compatible. The IBM BIOS is copyrighted by IBM, but "clone" makers either write their own or contract a company such as Phoenix to develop one for them that is compatible with, without infringing on, the copyrighted IBM BIOS. The measure of compatibility of a "clone's" BIOS is a major part of determining how compatible the machine as a whole is. First, some general information: The 8086 CPU and its sisters 8088, 80186, 80188, 80286, 80386 and 80486, all have certain registers (not to be confused with the CRTC registers) and instructions. The instruction of most concern to us is the "software INTerrupt request" instruction, or "INT" for short. It is followed by a number from 00h (0) to 0FFh (255), thus allowing for 256 different interrupt requests. The registers are as follows: Ú 8 bits  8 bits ¿ ÚÄÄÄ 16 bits ÄÄÄ¿ ÉÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍ» ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» º AH -A³X- AL º Accumulator º SP º Stack Pointer ÌÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍ͹ ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹ º BH -B³X- BL º Base º BP º Base Pointer ÌÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍ͹ ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹ º CH -C³X- CL º Count º SI º Source Index ÌÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍ͹ ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹ º DH -D³X- DL º Data º DI º Destination Index ÈÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍͼ ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ ÀÄÄÄ -16 bits- ÄÄÄÙ ÚÄÄÄ 16 bits ÄÄÄ¿ ÀÄÄÄ 16 bits ÄÄÄÙ ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ» Code Segment º CS º ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹ Data Segment º DS º ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹ Stack Segment º SS º ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹ Extra Segment º ES º ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ Note that the four 16-bit registers AX, BX, CX and DX each consist of two 8- bit registers, xH and xL, where "x" is the first letter of the 16-bit register name. AX consists of AH and AL, for example. The "H" means "High Byte" and the "L" means "Low Byte". So, the full name of the register "AH" is "Accumulator Register High Byte", while "CL" is "Count Register Low Byte", etc. We will use the abbreviations for the remainder of this article. The INT instruction, as I said before, simulates an interrupt to the processor. It can also be thought of as a short subroutine call. Unlike a true subroutine call, the program does not need to know the address of the subroutine in memory. The INT instruction gets this information from a special table of addresses in low memory. This means that a compatible BIOS need not have the same routines in the same memory as IBM's BIOS. This is fortunate, since it would be most difficult to make a compatible BIOS with the exact same entry point addresses for all routines without violating IBM's copyright! It also means that BIOS ROMs can be updated easily without sacrificing compatibility. Each INT number is assigned a specific device or service to perform. INT 10h (16 decimal) is reserved for video purposes. The registers must be loaded prior to performing the INT 10h, according to the desired results. Register AH is the most important, since it tells the Video BIOS routines which video related job to perform. So to call the Video BIOS, one must load the AH register with the number of the service to be performed, load any other registers as needed, then do an INT 10h. Upon return, certain registers may hold the results of the call (if any). Here is a list of the currently implemented BIOS calls which are compatible with the MDA and CGA boards: AH Function ÄÄ ÄÄÄÄÄÄÄÄ 00h Set video mode 01h Set cursor type 02h Set cursor position 03h Read cursor position 04h Read light pen position 05h Select display page 06h Initialize window or scroll window contents up 07h Initialize window or scroll window contents down 08h Read attribute and character at cursor 09h Write attribute and character at cursor 0Ah Write character only at cursor 0Bh Set color palette 0Ch Write graphics pixel (plot a dot) 0Dh Read graphics pixel 0Eh Write text in "teletype mode" 0Fh Get current video mode 10h Set palette registers (PCjr and EGA only) 11h Reserved (EGA: Character generator functions) 12h Reserved (EGA: Alternate function select) 13h Write string (PC/AT and compatibles only) There are others specifically implemented for the EGA, and others for Hercules boards and the like. These will be discussed in a later installment. For now, we will discuss Functions (AH) 00h through 0Fh: Function 00h ("Set video mode") does the following: It gets the desired mode number from the AL register, then determines which board (if multiple boards are installed in the system) to use. It then blanks the appropriate display temporarily by clearing the "Video" bit (bit 3) in the Control port (03x8h) of the appropriate board (see last issue). It then looks up in a table within the ROM BIOS for a list of the appropriate CRTC mode values (see the issue previous to the last one) and copies these to the 6845 CRTC chip by using the "CRTC_ Index" (03x4h) and "CRTC_Data" (03x5h) ports. It then determines the new values for the "Control" and "Color/Palette" (color boards only) ports and loads them in, re-enabling the video in the process by setting the "Video" bit in the "Control" port. Finally, it clears the appro- priate area of the video display buffer memory if the high bit was set in the AL (display mode) register. The standard modes for CGA, MDA, PCjr (VGA) and EGA boards are as follows: AL Video mode Boards supported ÄÄ ÄÄÄÄÄ ÄÄÄÄ ÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄÄ 00h 40x25 text, color burst off CGA, PCjr, EGA 01h 40x25 text, color burst on CGA, PCjr, EGA 02h 80x25 text, color burst off CGA, PCjr, EGA 03h 80x25 text, color burst on CGA, PCjr, EGA 04h 320x200 4-color graphics, color burst on CGA, PCjr, EGA 05h 320x200 4-color graphics, color burst off CGA, PCjr (EGA = 04h) 06h 640x200 2-color graphics, color burst off CGA, PCjr, EGA 07h 80x25 monochrome text MDA 08h 160x200 16-color graphics PCjr (16k video RAM) 09h 320x200 16-color graphics PCjr (32k video RAM) 0Ah 640x200 4-color graphics PCjr (32k video RAM) 0Dh 320x200 16-color graphics EGA w/CGA or EGA monitor 0Eh 640x200 16-color graphics EGA w/CGA or EGA monitor 0Fh 640x350 4-attribute monochrome graphics EGA w/MDA monitor 10h 640x350 4-color graphics EGA w/EGA monitor, 64K 10h 640x350 16-color graphics EGA w/EGA monitor, 128K+ Function 01 ("Set cursor type") sets the starting and ending lines for the blinking hardware cursor in text modes. The default values for the cursor which are set by Function 00h (see above) are 6 and 7 for EGA, or 11 and 12 for MDA. This is done by setting the 6845 CRTC registers "Cursor_Start" and "Cursor_End". Register CH's low 4 bits hold the starting scan line value, and register CL's low 4 bits hold the ending scan line value; both of which can range from 0-15. Setting the starting value to 15 will usually make the cursor disappear. Function 02h ("Set cursor position") moves the cursor to a specified position on the text display, using text rows and columns as the coordinates. This is far easier than using the CRTC "Cursor_High" and "Cursor_Low" registers, since those registers point to the cursor's absolute memory location within the display buffer. The BIOS call automatically converts the specified screen coordinates to the proper memory location, then loads the CRTC Cursor registers appropriately. Register BH contains the video page number (usually 0). Register DH contains the text row (0-24), while DL contains the text column (0-39 or 0-79). A more reliable way to hide the cursor than using Function 01h (see above) is to use Function 02h to move the cursor off the screen, say to Row 25. Function 03h ("Read cursor position") does the reverse of Function 02h. It reads the CRTC "Cursor_High" and "Cursor_Low" registers, takes that absolute address and converts it to a text row and column, and loads the DH and DL registers with those coordinates. Before the call, Register BH must be set to the video page number (usually 0). After the call, register DH will contain the text row (0-24) while DL will contain the text column (0-39 or 0-79). Function 04h ("Read light pen position") will be discussed at a future time, if enough readers express interest in how to program a light pen. Function 05h ("Select display page") selects which page to display in a video board/mode combination that supports multiple pages. For the CGA, it does this by setting the CRTC "Start_High" and "Start_Low" registers to a multiple of 2K (0800h) for 40-column text modes (8 pages, numbered 0-7), or 4K (1000h) for 80-column text modes (4 pages, numbered 0-3). The EGA supports 8 pages in the 80-column text modes as well, and also supports up to 8 pages in the 320x200 16-color graphics mode, up to 4 in the 640x200 16-color mode, and up to 2 in both 640x350 modes (these limits assume 256K of on-board video RAM). For the standard PC and PC/AT, register AL holds the desired page number. On the PCjr, AL holds a sub-function code, and register BX either holds or returns the desired page number(s). Note that many functions which write to the display allow the specification of a page number. This means that the page being displayed can be separate from the page being written to. This allows for smooth animation or fast screen-changing effects. Function 06h ("Initialize window or scroll window contents up") and Function 07h ("Initialize window or scroll window contents down") allow the specification of a rectangular text area, or "window", which can then be cleared or scrolled independently of the rest of the screen. By setting the window to cover the full screen, the entire screen is either scrolled or cleared. This is how normal screen-clearing and text-scrolling operations are performed. Register AL contains the number of lines to scroll, or 0 to clear the window. Register BH contains the attribute to be used for the area left blank by the scroll or clear. Registers CX and DX contain the bounds of the window as follows: Register Range(s) Meaning ÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÄ CH (0-24) Top text row, or upper left corner's Y. CL (0-39/79) Left text column, or upper left corner's X. DH (CH-24) Bottom text row, or lower right corner's Y. DL (DL-39/79) Right text column, or lower right corner's X. Of course, these two functions are identical except for the fact that Function 06h scrolls up and Function 07h scrolls down. Either can be used to clear the window or screen. Note that only the currently-active display page is affected (see Function 05h above). Both functions use some RAM locations to reset the Control and Palette ports to legitimate values. This causes any changes made to them to "vanish" after a BIOS scroll or screen clear. Next issue we will discuss a way to get around this. Function 08h ("Read attribute and character at cursor") loads Register AX with the attribute byte (in AH) and the ASCII character code (in AL) at the current cursor position in the text page specified by Register BH. Function 09h ("Write attribute and character at cursor") places a desired character (ASCII code in AL) with a specified attribute byte or color code (in BL) at the current cursor location in the specified video page (in BH). It does this CX times, thus a row of a certain character can be "drawn" with a single call. The cursor is NOT moved by this call, and no characters are considered "special" in any way -- not even return, line feed, backspace or bell. In graphics mode, the characters are "drawn" by plotting 8 pixels at a time; and if the high bit (bit 7) of the attribute byte (in BL) is set, the characters will be drawn in XOR mode, which means that they can overwrite a complex graphics background, then simply re-plotting the text will seem to erase them, restoring the previous contents of the graphics under the "text"; and the bit patterns for characters whose ASCII codes are greater than 7Fh (127) can be programmed. Function 0Ah ("Write character only at cursor") is identical to Function 09h (see above) except that the attribute at that character position remains the way it was. In graphics mode, the BL register's high bit can still be used to specify XOR mode. Other than that, regiester BL's contents are ignored Function 0Bh ("Set color palette") on the CGA sets the "CGA_Palette" register as follows: If BH=0, BL contains the 4 bits to load into the low nybble of the Palette register, thus setting the border color in text modes, the background color in 320x200 graphics modes, and the foreground color in the 640x200 graphics mode. If BH=1, BL contains either a 0 or a 1, which is loaded into the "CGA_P_Palette" bit of the "CGA_Palette" register, thus changing the current 320x200 color graphics palette. BL=0 selects the Green-Red-Yellow palette, while BL=1 selects the Cyan-Magenta-White palette. For the PCjr, this function can be used to select individual palette colors. Function 0Ch ("Write graphics pixel") plots a point on the graphics screen. For CGA, location AL must be loaded with the value of the color to plot the dot with (0-3 in 320x200 4-color modes, 0-1 in 640x200 2-color mode) -- the high bit can be set to do the plot in XOR mode. Register CX contains the horizontal, or X-coordinate of the pixel (0-319 in 320-wide modes, 0-639 in 640-wide modes); while Register DX contains the vertical, or Y-coordinate of the pixel (0-199 in 200-line modes, 0-349 in 350-line EGA modes). Function 0Dh ("Read graphics pixel") is used to determine the color of a specified pixel in the graphics modes. The coordinates must be loaded into registers CX and DX the same as in Function 0Ch (see above). After the call, register AL holds the pixel value, or color. Function 0Eh ("Write text in 'teletype' mode") is similar to Function 0Ah ("Write character only at cursor" -- see above), except that the cursor IS moved to the next position, unless the character is a linefeed (cursor is moved down one line), carriage return (cursor is moved to the first position on the line), backspace (cursor is moved backwards one position), or bell (cursor is not moved, but the speaker sounds a tone). Automatic line-wrapping and screen- scrolling are also provided by this function. If the screen is scrolled, this function automatically calls Function 06h ("Initialize window or scroll window contents up") to scroll the screen, passing as the "fill" attribute the attribute of the last character to be written before the scroll. There is no way to specify the attribute of a text character with this function. If you wish to set attributes, you should write each attribute with Function 09H ("Write attribute and character at cursor" -- see above) with a space character (20h, 32), followed by this Function to write the character with proper cursor movements. This is the BIOS call that MS-DOS uses for its console driver (CON) output. As in Functions 09h and 0Ah, register BH holds the desired text page, and register BL holds the color to use in graphics mode text plotting. The repeat factor (CX) is not used here. Function 0Fh ("Get current display mode") gets the currently active display mode (set with Function 00h -- see above) and the current display page (set with Function 05h -- see above). No registers (except for AH containing the Function code 0Fh, of course) need be set prior to the call. Upon return, AL contains the current mode (as per Function 00h) and BH contains the active display page. Performing INT calls from BASICA or GW-BASIC can be difficult. It basically requires a machine-language routine to be made available. Turbo Pascal, on the other hand, provides a nice programmer's interface to the INT function. One simply defines a RECORD VARiable to hold the registers, then call the "Intr" PROCEDURE with the desired INT code and registers variable. These lines will define the TYPE and VARiable that the "Intr" (and "MsDos") PROCEDUREs expect: ^1TYPE ^1 ... ^1 iAPX = RECORD CASE Boolean OF ^1 False: (AX, BX, CX, DX, BP, SI, DI, DS, ES, Flags): Integer; ^1 True: (AL, AH, BL, BH, CL, CH, DL, DH): Byte ^1 END; { RECORD iAPX } ^1 ... ^1VAR ^1 ... ^1 registers: iAPX ^1 ... As an example, to scroll a window on the 80x25 text screen consisting of rows 5-20 and columns 10-70 4 lines downward, filling the new blank lines with a dark red background with a light yellow (but invisible, since there is no text) foreground, you could do this: ^1PROCEDURE scroll4down; ^1 BEGIN { PROCEDURE scroll4down } ^1 WITH registers DO BEGIN ^1 CH := 5; { Top row of window } ^1 DH := 20; { Bottom row of window } ^1 CL := 10; { Left column of window } ^1 DL := 70; { Right column of window } ^1 BH := (Red SHR 4) OR Yellow; { Fill attribute = $4E } ^1 AL := 4; { Lines to scroll } ^1 AH := $7 { "Initialize window or scroll window contents down" } ^1 END; { WITH registers } ^1 Intr ($10, registers) { BIOS call, $10 = Video services } ^1 END; { PROCEDURE scroll4down } On this issue of Big Blue Disk is a demo program which demonstrates the various BIOS calls discussed here. Simply press the [ÄÙ] key to run it from here, or you can press [Esc] to get back to the menu, re-select this article, and choose "Run it" from the menu. Next issue we will discuss how the BIOS keeps track of certain information, and how one can obtain very interesting effects by "tricking" the ROM BIOS. Two effects in particular will be to enable bright background by sacrificing the blink capability, but enable that effect to survive a Function 06h or 07h scroll or screen clear; and to trick BIOS into thinking you've switched graphics modes when you haven't, thus allowing both 40-column and 80-column text on the screen at the same time in 640x200 graphics mode.