Exploring the EGA, Part 2 (PC Magazine Vol 5 No 15 Sept 16, 1986 by Charles Petzold) As in part 1, most of the programs presented here are in the form of DEBUG "script" files. To create executable .COM files: DEBUG < filename.SCR Background on Fonts As with the old CGA, the EGA supports both text and graphics video modes. In text modes the ASCII codes of the displayed characters are stored in video memory. The adapter hardware translates these characters into dots through the use of a font table that contains the dot patterns for all 256 characters. In graphics modes the dots themselves are stored in memory, and the adapter hardware simply translates these dots into video signals. For programs that need display only normal text, text modes are preferable because they require less video memory and can be manipulated more rapidly by applications programs. The CGA and the IBM Monochrome Adapter use a font table stored in ROM on the adapter board. This ROM is not accessible from software, and programs may not load a different font in text modes. The only way to change the font is to remove the ROM chip from the adapter board and substitute your own. These adapters are also generally limited to 25 lines of text on the screen. (The 6845 CRT Controller chip on these boards can be programmed for a 50-line interlace mode, but it looks awful.) The EGA text modes work a little differently. The adapter memory contains both the font table and the ASCII codes of the displayed characters. The EGA BIOS downloads the appropriate font into the EGA memory when it sets the video mode. The fonts are stored in the EGA BIOS, and the programs have complete access to them through a BIOS call that returns a pointer to the stored fonts. Following a video mode set, you can also call the BIOS to download your own font into EGA memory. At the same time, you can change the number of displayable character rows on the screen. (Of course, in EGA graphics modes a program can write whatever dots it wants to the screen and could even create proportionally spaced fonts. In character modes you don't have quite this same flexibility.) The fonts used in EGA text modes have some limitations. The most severe restriction is that the width of each character is fixed at 8 dots. This includes the space between characters, so in most cases characters will be only 7 dots wide. The character height, however, may range from 1 to 32 scan lines. The maximum number of displayable character rows on the screen is equal to the total number of displayable scan lines (200 for the old Color Display and 350 for the Monochrome Display and Enhanced Color Display) divided by the number of scan lines per character. The EGA BIOS contains complete fonts for an 8-by-8 character set (8 scan lines per character) and for an 8-by-14 character set (14 scan lines). You can get the starting address of these fonts in the EGA BIOS by simple Interrupt 10h calls. These fonts are stored in the BIOS in a simple format. The order of the characters is sequential by ASCII code. Each character is defined by a series of bytes, with the number of bytes used by each character equal to the height of the character in scan lines. The first byte contains the dot patterns for the top scan line. The most significant bit of each byte corresponds to the leftmost dot of the character. The least significant bit is usually 0 to allow for the space between characters. Thus the character box is 8 dots wide, while the characters are generally 7 dots wide. The line- and box-drawing characters (ASCII codes C0h through DFh) are 8 dots wide, so they connect on the horizontal. (The Monochrome Displays requires separate mention here, as its character box is actually 9 dots wide. For most characters, however, the 9th dot will be displayed as background. For the block- and line- drawing characters (ASCII codes from C0h through DFh) the EGA makes the 9th dot the same as the 8th dot, so the characters connect on the horizontal. The EGA BIOS stores what is called a 9-by-14 font, but it is not a complete font. For all but 20 characters, the EGA uses the same 8-by-14 font used for the Enhanced Color Display. The 9-by-14 font contains alternative dot patterns for these exceptions. The storage format is different from that of the other fonts: Each character requires a 1-byte ASCII code, followed by 14 bytes for the dot patterns. The entire 9-by-14 font is terminated by a zero. This 9-by-14 font allows monochrome characters to be 8 dots wide, since the 9-dot width of the character box still leaves a space between characters. If you'll be creating your own fonts, however, you may want to forget about this peculiarity. For greatest versatility, you can use an 8-dot-wide character box with a 7-dot-wide character for both the Enhanced Color Display and the Monochrome Display.) In text modes that use 200 scan lines on the screen (video modes 0 through 3 when an EGA is connected to an old Color Display), the EGA normally uses the 8-by-8 font putting 25 character rows on the display. Connected to an Enhanced Color Display or Monochrome Display, the EGA displays 350 scan lines, so the text modes (monochrome mode 7 and color modes 0 through 3) use the 8-by-14 font, again creating 25 character rows. However, if you use the 8-by-8 font in a 350-scan-line video mode, you can display 43 character rows, since 43 times 8 equals 344. A font that is 10 scan lines high (which can be the 8-by-8 font with 2 blank scan lines) allows 35 displayable rows. If you create your own 8-by-6 font, you can fit 58 lines on the screen. These alternative displays are supported by the EGA BIOS. What this "BIOS support" means is very simple: The EGA stores the current number of lines per screen (less 1) at address 0000:0484h. An application can also obtain this information by an Interrupt 10h call. The BIOS Teletype routine (Interrupt 10h, Function call 0Fh), which is normally used for screen output at the DOS command level (except when ANSI.SYS is loaded), uses this value to determine when to scroll the screen. Font Changes Through the BIOS Even if you're not the type of person who would like to see everything on the screen in italic, it's well to begin by trying out the EGAITAL program. Because it loads a 14-scan line character font, this program can be used only with EGAs attached to Enhanced Color Displays or Monochrome Displays. EGAITAL.SCR: N EGAITAL.COM A 100 CLD MOV BH,02 ;Get 8x14 font MOV AX,1130 INT 10 ;Returns ES:BP PUSH ES POP DS MOV SI,BP ;DS:SI points to font PUSH CS POP ES MOV DI,0159 ;ES:DI = destination MOV BX,0100 ;Number of characters MOV CL,03 ;MAINLOOP: CALL 0147 ;Call SHIFTRIGHT CALL 0147 ;Call SHIFTRIGHT CALL 0147 ;Call SHIFTRIGHT CALL 0150 ;Call SHIFTLEFT CALL 0150 ;Call SHIFTLEFT CALL 0150 ;Call SHIFTLEFT CALL 0150 ;Call SHIFTLEFT DEC BX ;Decrement char count JNZ 0114 ;Loop if not zero MOV BP,0159 ;Point to font SUB DX,DX ;Starting character MOV CX,0100 ;Character count MOV BH,0E ;Bytes per character CS: MOV BL,[005D] AND BL,03 ;Block to load MOV AX,1100 ;Load font INT 10 INT 20 ;Terminate LODSW ;SHIFTRIGHT: SHR AL,CL SHR AH,CL STOSW ;and store DEC CL RET LODSW ;SHIFTLEFT: SHL AL,CL SHL AH,CL STOSW ;and store INC CL RET R CX 59 W Q In EGAITAL, the first INT 10h call (where AX equals 1130h) returns a pointer to the 8-by-14 font stored in the EGA BIOS. You can get a pointer to the 8-by-8 font by setting BL to 3, and to the 9-by-14 font extension by setting BL to 5. This function call also returns the current number of character rows (less 1) in register DL and the current number of scan lines per character (called "POINTS" in the BIOS documentation) in register CX. Next, EGAITAL transfers the font to local memory and, in the process, shifts each byte to tilt the character to the right. (If you think that doing bit manipulations on existing fonts is a flaky way to create new fonts, that's how Microsoft Word does italics in EGA graphics modes, although Word uses a different algorithm that is not quite as extreme.) Finally, EGAITAL makes another BIOS call to load the font. This is Function Call 11h (in AH), subfunction 00h (in AL), which is used to load a user font when the number of displayable rows does not change. Although you're loading all 256 characters starting at ASCII code 00, you can load only part of a character set by setting registers CX and DX appropriately. You can go back to the normal font by resetting the video mode with EGAMODE (see Part 1 of this article) or by executing the program EGA8X14 below. This latter program uses another, simpler BIOS call in which register AH again equals 11h but in which AL equals 01. This loads the normal 8-by-14 font. If AL were 03, the 8-by-8 font would be loaded, but you wouldn't be happy with the way it looked. Since the EGA is still using 14 scan lines per character, the bottom 6 scan lines will display the bottom of the 8-by-14 font. EGA8X14.SCR: N EGA8X14.COM A 100 MOV AX,1101 ;Load 8x14 font MOV BL,0 ;Block to load INT 10 ;Call BIOS INT 20 R CX 9 W Q Incidentally, when you execute these programs, you may see a brief contraction of your display (and it may even roll over once) when the font is loaded. This is normal. The EGA BIOS has to change the video mode to one of the internal modes (11 and 12) so it can access the video memory to load the font. Then it must change the mode back to the original mode. Changing the Displayable Rows The Interrupt 10h function calls used in the previous examples (where AH is 11h and AL equals 00, 01, or 02) simply load the font. When AL equals 10h, 11h, or 12h, the BIOS loads the font and recalculates the number of displayable rows on the screen based on the new character height. The BIOS also recalculates the cursor and monochrome underline position, but it does so incorrectly, causing the cursor on an Enhanced Color Display and the underline on the Monochrome Display to disappear. All the EGA-compatible boards seem to duplicate this bug. Note also that the video page size is recalculated. Programs that directly access the video memory of different pages should use the CRT_LEN value stored at memory location 0000:044Ch for the length of a video page. Programs should not follow the example of ANSI.SYS, which hardcodes a page size. Because of the recalculations the BIOS must make when using these function calls, the IBM documentation recommends you execute them right after a video mode set. That's not really necessary, but you should be using video page 0 (which is normal) and, if you're changing to a smaller number of displayable lines, your cursor should be somewhere near the top of the display, on a row lower than the number of rows you'll be changing to. In any case, if while fooling around with these programs your cursor ends up somewhere below the bottom of the displayable screen, just enter EGAMODE 3 (for color) or EGAMODE 7 (for monochrome) to return to normal. The most popular of the new EGA screen formats is the 43-line mode. EGA43 implements it. The program also fixes the cursor on the Enhanced Color Display and the underline on the Monochrome Display. If you haven't loaded ANSI.SYS (or some other resident program that messes around with the screen), you'll see that commands such as DIR work fine with 43 rows. Any program that uses DOS for simple teletype screen output (such as EDLIN and DEBUG) will also use the 43 rows. EGA43.SCR: N EGA43.COM A 100 MOV AX,1112 ;Load 8x8 font MOV BL,00 INT 10 SUB AX,AX MOV DS,AX PUSH [0487] ;Save INFO byte OR BYTE PTR [0487],01 MOV CX,0600 ;Set cursor size MOV AH,01 INT 10 POP [0487] ;Restore INFO byte MOV DX,03B4 ;Fix up underline MOV AX,0714 OUT DX,AX INT 20 R CX 28 W Q Note, however, that DIR /P (which pauses after a full screen) assumes the display has 25 rows. Until the EGA, there was no BIOS call that returned the number of displayable rows on the screen, so most programs that need to know the number of rows on the screen just use 25. If the developers of the original PC BIOS had had the foresight to allow for an adapter capable of more than 25 rows, this would not be a problem. Because of this deficiency in the original system board BIOS, you'll find that full-screen applications programs will react to the 43-line mode in one of three ways. If the program resets the video mode on entry, the display will go back to 25 lines. If the program does not reset the mode, it will probably use only the top 25 lines of the screen. However, EGA-aware programs are starting to appear that will pick up the information from the EGA BIOS and use all 43 lines. For example, BROWSE.COM (PC Mag Vol 5 No 6) will use all 43 lines. And some commercial programs, such as XyWrite III and Microsoft Word 3, have an option to use the EGA in its 43-line mode. If you have loaded ANSI.SYS, even the one that comes with DOS 3.2, you'll see that it assumes the display has 25 rows. ANSI.SYS users might want to look up Hersey Micro Consulting's Fansi-Console, v1.15, which, along with many other valuable features, supports ANSI functions on the EGA in different screen formats. If 43 lines seem too cramped for you, how about 35 lines? The EGA35.COM program retrieves a pointer to the 8-by-8 font from the BIOS but stores the font in local memory with 2 blank scan lines at the end of each character. It then loads the font (which is now, since we've changed it, a user-defined font) into the EGA through another BIOS call. EGA35.SCR: N EGA35.COM A 100 CLD MOV BH,03 ;8x8 font pointer MOV AX,1130 INT 10 PUSH ES POP DS MOV SI,BP ;DS:SI points to font PUSH CS POP ES MOV DI,0152 ;ES:DI to destination MOV BX,0100 ;Number chars MOV CX,0008 ;Bytes per char REPZ ;Move them MOVSB SUB AX,AX ;Store two zeros STOSW DEC BX JNZ 0114 ;Next character MOV BP,0152 ;Points to font MOV DX,0000 ;Starting char MOV CX,0100 ;Number of chars MOV BH,0A ;Bytes per char MOV BL,00 ;Block to load MOV AX,1110 ;Load user font INT 10 SUB AX,AX MOV DS,AX PUSH [0487] ;Fix up cursor OR BYTE PTR [0487],01 MOV CX,0800 MOV AH,01 INT 10 POP [0487] MOV DX,03B4 ;Fix up underline MOV AX,0914 OUT DX,AX INT 20 R CX 52 W Q On the other hand, if 43 lines are not quite enough, you may want to try out EGA50.COM. It loses the descenders on the lowercase letters and makes commas look like periods, but it's still readable. EGA50.SCR: N EGA50.COM A 100 CLD MOV BH,03 ;8x8 font pointer MOV AX,1130 INT 10 PUSH ES POP DS MOV SI,BP ;DS:SI points to font PUSH CS POP ES MOV DI,0150 ;ES:DI to destination MOV BX,0100 ;Number of chars MOV CX,0007 ;Bytes per char REPZ ;Move them MOVSB INC SI ;Skip over last byte DEC BX JNZ 0114 ;Next character MOV BP,0150 ;Points to font MOV DX,0000 ;Starting char MOV CX,0100 ;Number of chars MOV BH,07 ;Bytes per char MOV BL,00 ;Block to load MOV AX,1110 ;Load user font INT 10 SUB AX,AX MOV DS,AX PUSH [0487] ;Fix up cursor OR BYTE PTR [0487],01 MOV CX,0600 MOV AH,01 INT 10 POP [0487] MOV DX,03B4 ;Fix up underline MOV AX,0614 OUT DX,AX INT 20 R CX 50 W Q For something a little taller on your screen, use EGA12.COM. It doubles up the dots of the 8-by-14 font and creates a 12-line display. While this looks a little strange in an 80-column mode, try executing it after EGAMODE 1. This is a 12-line by 40-column display. Once again, commands like DIR are very happy with this format. EGA12.SCR: N EGA12.COM A 100 CLD MOV BH,02 ;Get font pointer MOV AX,1130 INT 10 PUSH ES POP DS MOV SI,BP ;DS:SI points to font PUSH CS POP ES MOV DI,014C ;ES:DI is destination MOV CX,0300 ;14 bytes per char LODSB ;Get bytes STOSB ;Store it twice STOSB LOOP 0114 ;Keep going MOV BP,014C ;Points to font MOV DX,0000 ;Starting char MOV CX,0100 ;Number of chars MOV BH,1C ;Bytes per char MOB BL,00 ;Block to load MOV AX,1110 ;Load font INT 10 SUB AX,AX MOV DS,AX PUSH [0487] ;Fix up cursor OR BYTE PTR [0487],01 MOV CX,1619 MOV AH,01 INT 10 POP [0487] MOV DX,03B4 ;Fix up underline MOV AX,1B14 OUT DX,AX INT 20 R CS 4C W Q Finally, EGA25.COM returns things back to normal. EGA25.SCR: N EGA25.COM A 100 MOV AX,1111 ;Load 8x14 font MOV BL,00 INT 10 SUB AX,AX MOV DS,AX PUSH [0487] ;Fix up cursor OR BYTE PTR [0487],01 MOV CX,0B0D MOV AH,01 INT 10 POP [0487] MOV DX,03B4 ;Fix up underline MOV AX,0314 OUT DX,AX INT 20 R CX 28 W Q EGA43.COM, EGA35.COM, EGA50.COM, EGA12.COM, and EGA25.COM may be run on EGAs attached to Enhanced Color Displays or Monochrome Displays. If you have your EGA attached to a regular old Color Display, you have only 200 scan lines to work with. EGA43 will make your display use the normal 25 lines, EGA50 will turn it into a 28-line display, EGA35 will do 20 lines, EGA12 will do 7 lines, and EGA25 will do 14 lines. The Problems of Cursor Emulation In the programs above, code was added to fix the monochrome underline and the color cursor. The fix to the monochrome underline is necessary because of a simple bug in the EGA BIOS. The fix to the color cursor is necessary because of a more complex bug. Programs that set a cursor size usually assume that each character in a color mode has 8 scan lines. Setting the cursor to scan lines 6 and 7 creates the normal underline cursor. On the EGA, however, this would put the cursor in the middle of the character. For this reason, the EGA BIOS uses "cursor emulation" logic to translate a cursor size into something appropriate for a 14-scan-line character. (The cursor registers in the EGA also function differently from those in the CGA.) This cursor emulation algorithm, however, is based on the presence of an Enhanced Color Display rather than on the size of each character. In the sample programs shown here, therefore, we first turn off cursor emulation by flagging a bit in lower memory and then restoring the bit when we're done. You probably won't want to turn cursor emulation off entirely because programs that set the cursor size through the BIOS will then put the color cursor on scan lines 6 and 7 when your normal character set is 14 scan lines high. Even with cursor emulation on, you may see this problem with programs that go directly to CRT registers to set the cursor size. Once again, this is a problem that could have been avoided had the designers of the original system board BIOS foreseen an adapter that had a variable number of scan lines per character and created a memory location (like the one the EGA BIOS maintains) to store this value. A New Print Screen Routine Did you try a Shift-PrtSc while in 35- or 43-line mode? Were you surprised to find that only the top 25 lines printed on your printer? That happens because the Interrupt 5 Print Screen routine in effect is still the one in the system board BIOS, which is locked into using 25 lines per screen. Fortunately, the EGA has its own Print Screen routine. It's virtually identical to the one in your system board BIOS except that it uses a variable number of lines per screen. When the EGA boots up, however, this new Print Screen routine is not automatically substituted for the old one. EGAPRTSC.COM rectifies this oversight by substituting the EGA Print Screen routine for the one in your system board BIOS. If you intend to regularly use the various alternative screen formats included here, EGAPRTSC should be part of your AUTOEXEC.BAT file, and it should be very close to the top. It should be executed early because if you load EGAPRTSC after any resident program that also uses Interrupt 5 (e.g., the DOS GRAPHICS program and some print buffers), these other programs will be locked out. EGAPRTSC.SCR: N EGAPRTSC.COM A 100 MOV AH,12 ;Select Alternate MOV BL,20 ; Print Screen INT 10 INT 20 R CX 8 W Q Of course, the EGA Print Screen routine does not support the printing of graphics screens created in EGA graphics modes. (Neither does the DOS GRAPHICS program.) Nor will you be able to print the alternative fonts that you load into the EGA. A New Clear Screen When using screen lengths of more than 25 lines, you'll find that CLS no longer works right, either. It, too, suffers from the curse of the original PC in having to assume 25 lines on the screen. The new EGA-aware Clear Screen program (CS.COM) uses the BIOS call to determine the number of lines on the screen (actually one less than the total). To maintain compatibility in case the program is used on a system without an EGA, it first sets DL to 24 before making the call. If an EGA is not installed, the system board BIOS will just return all the values of registers unchanged. CS.SCR: N CS.COM A 100 MOV DL,18 ;24 columns default SUB BH,BH ;Get number of columns MOV AX,1130 INT 10 MOV AH,0F ;Get video information INT 10 DEC AH MOV CH,DL MOV CL,AH ;CX = maximum row and column MOV AH,00 ;Graphics attribute CMP AL,07 ;See if monochrome mode JZ 011D CMP AL,03 ;See if text mode JA 012D MOV DL,20 ;Write space to display MOV AH,02 INT 21 MOV AL,08 ;Backspace MOV AH,0E INT 10 MOV AH,08 ;Read attribute INT 10 PUSH BX ;Save video page MOV BH,AH ;Clear screen MOV DX,CX SUB CX,CX MOV AX,0600 INT 10 POP BX ;Get back video page SUB DX,DX ;Home cursor MOV AH,02 INT 10 INT 20 R CX 42 W Q The problem is different from CLS in some other ways. It doesn't ignore the screen color attribute currently in effect and doesn't wipe out a border (as CLS does when ANSI.SYS is not loaded), nor does it turn the screen white for graphics modes (as the ANSI.SYS CLS does). A 43-Line WordStar WordStar, of course, is one of the few applications programs that can be easily patched for different screen formats. The patch points have been well documented and have remained consistent (in most cases) from version to version. If you'll be using DOS in a 43-line mode, all you have to do to get WordStar to use 43 lines is to change the value at offset 248h from 18h (which is 24 decimal) to 2Ah (42) or 2Bh (43). Using the latter value eliminates the display of the function keys down at the bottom of the screen. If you'll be using DOS with 25 lines but want to use WordStar with 43 lines, the file below shows a patch to WordStar to switch to the 43-line mode on entry and restore 25 lines on exit by resetting the video mode. This patch assumes that nothing else is located in the WordStar patch area at offset 2E0h. You can patch your copy of WS.COM and create a new version of WordStar WS.COM called WS43.COM by putting WS43.SCR on the same disk or in the same subdirectory with WS.COM and executing: DEBUG < WS43.SCR WS43.SCR: N WS.COM L N WS43.COM E 248 2A A 2A4 JMP 2E1 ;Initialize Screen NOP JMP 300 ;De-initialize A 2E1 MOV AH,0F ;Get Video Mode INT 10 MOV [2E0],AL ;Save it SUB BL,BL ;Use 43 column mode MOV AX,1112 INT 10 MOV CX,0007 ;Set cursor to block MOV AH,1 INT 10 RET A 300 MOV AL,[2E0] ;Get back mode SUB AH,AH ;And reset INT 10 RET W Q If you'd rather get an extra line of text instead of the function key definitions down at the bottom, change the line reading: E 248 2A to E 248 2B The 512-Character Set So far we've been looking at fonts that are simply substituted for the font normally loaded by the BIOS. However, an EGA equipped with 256K can actually store four entire 256-character fonts in its memory. If your EGA has 128K, it can hold two fonts. A 64K EGA is limited to one font. Usually only one of these fonts is active at any one time, but you can tell the EGA which one you want to be active by using a simple BIOS call. In addition, you can select any two of the four fonts to be active at the same time on the same screen. Instead of a normal 256-character set, this lets you use a 512-character set. Since the ASCII code for each character is still limited to 1 byte, something else outside the character code has to specify which font is to be used for each character. This "something else" is the attribute bit that normally indicates foreground color intensity. Instead of (or in addition to) making a character high intensity, this bit selects the alternate font. Thus if your word processor can display all 256 normal characters and can also use high intensity to represent boldface on the screen, you can use boldface instead to select an additional 256 different characters on your screen. You may have noticed that in the font-loading examples shown so far, register BL was always set to zero. Register BL specifies what the EGA BIOS calls the "Block to Load." This register can be set to any value from 0 through 3, and it corresponds to the four fonts you can load into an EGA equipped with 256K. If the value of BL is set to 1, the font is loaded into block 1 instead of block 0. Since block 0 is normally used for both low-intensity and high-intensity characters, you won't see a change in your display until you instruct the EGA to use the intensity bit to select the alternative font. An example will make this clearer. EGAITAL.COM can actually take a parameter that specifies the block (0 through 3) into which to load the font. If no parameter is specified, it loads the font into block 0. But now try running: EGAITAL 1 Earlier, when we ran EGAITAL with no parameter, the text on the screen became italic. Now, nothing happens. The italic font has been loaded into the EGA memory, but in block 1 instead of block 0. Block 0 still contains the normal font. Now we have to tell the EGA two things: first, that we want block 0 to be used for low-intensity characters and block 1 to be used for high intensity; second, that we want to suppress the normal use of the intensity bit in the attribute byte. EGA512.COM will do this. It takes two parameters that may range from 0 through 3. The first parameter indicates the font to use on low-intensity characters; the second is the font to use for high- intensity characters. If you execute: EGA512 0 1 anything that is high intensity on your screen will become low- intensity italic. Anything that is low intensity will remain the same. EGA512.SCR: N EGA512.COM A 100 MOV BL,[005D] ;1st Parameter AND BL,03 ;Lower 3 bits MOV BH,[006D] ;2nd Parameter AND BH,03 ;Lower 3 bits MOV CX,BX ;Save in CX SHL BH,1 ;Shift BH left SHL BH,1 OR BL,BH ;Combine with BL MOV AX,1103 ;Set block spec. INT 10 MOV BX,0F12 ;Enable all planes CMP CL,CH ; but only if JZ 0124 ; blocks are equal MOV BH,07 ;Otherwise low MOV AX,1000 ;Enable planes INT 10 INT 20 R CX 2B W Q To prove this, execute TEST512. This program prints two lines, one in low intensity and one in high intensity. The high-intensity line will not be high intensity, but, rather, will be italic. Now, if you execute: EGA512 1 0 everything in low intensity will be italics (the block 1 font), and everything in high intensity will be the normal font (block 0). Finally, EGA512 0 0 turns everything back to normal. It makes both low intensity and high intensity have the same font. The EGA512 program checks if the two parameters are the same and, if so, restores the meaning of the attribute bit to specify high intensity. TEST512.SCR: N TEST512.COM A 100 MOV AH,0F ;Get video page INT 10 MOV AH,03 ;Get cursor INT 10 MOV BP,0128 ;String 1 MOV CX,000F ;Number of chars MOV BL,07 ;Attribute MOV AX,1301 ;Write String INT 10 MOV AH,03 ;Get cursor INT 10 MOV BP,0137 ;String 2 MOV CX,0010 ;Number of chars MOV BL,0F ;Attribute MOV AX,1301 ;Write String INT 10 INT 20 DB "Low Intensity",0D,0A DB "High Intensity",0D,0A R CX 47 W Q If your word processor works in text mode, does on-screen display of boldface, and doesn't reset the video mode on entry, try executing: EGA512 0 1 and see if you can get italic in your word processor instead of boldface. (Of course, then you have the problem of printing those extra 256 characters on your printer. But this is an article about video. Your printer is a whole other problem.) You may be distressed at losing a high-intensity character display when you use the 512-character set, but there's a way around that, too. In Part 1, the EGA palette registers were used to map the 4-bit IRGB code into a 6-bit rgbRGB code. With this technique you can map the low-intensity IRGB codes (where the "I" intensity bit is 0) into high-intensity rgbRGB codes. The only thing you're really limited to with a 512-character set is 8 foreground colors instead of 16 for the two fonts, since only the RGB bits of the attribute (and not the I bit) are used for foreground intensity. Using the palette registers, you can map these into anything you want. Another alternative to restoring high-intensity foreground is to invert all the bits of the two fonts and use another BIOS call (AX = 1003h and BL = 0) to enable background intensity instead of blinking. Now, since your characters are really background, you have all 16 colors available for the two fonts. Your background is now limited to 8 colors (which is normal), and you can't use hardware blinking. The underline on the monochrome display presents another problem. If you decide to remap palette registers to give you low and high intensity for each font, you'll be able to use an underline only in either low or high intensity, but not both. The Poor Man's Font Editor Now that you've seen how you can load fonts into the EGA, you may want to create your own fonts. There are two ways to do it. You could start off with a piece of graph paper, draw each character by coloring in the appropriate blocks, translate each row of dots into a two-digit hexadecimal number, and then type these numbers into a file. This is the long way. It's easier to use an on-screen "font editor" program. You can then begin with an existing font and make modifications to it. Of course, font editors can be complex, but we'll taking an inexpensive approach by turning your own text editor into a font editor. You'll be editing an assembly language file that contains a series of assembler "DB" statements. You can then convert this file back into bytes with the IBM or Microsoft Macro Assembler. FONT2DB.COM retrieves an existing EGA font and translates it into these DB statements. The file created by this program is quite long: there are 256 characters and 14 bytes per character (for the 8-by-14 font), and each byte uses one line. The bytes are shown in binary format as 0s and 1s, so you get a visual representation of the font on your screen. Although FONT2DB is set up to list the 8-by-14 font, the values are shown in FONT2DB.SCR to change to use it for the 8-by-8 font. FONT2DB.SCR: N FONT2DB.COM A 100 MOV BH,02 ;03 for 8x8 font MOV AX,1130 INT 10 ;ES:BP points to font MOV CX,0100 ;Number of characters MOV BH,0E ;08 for 8x8 font ES: MOV DH,[BP+00] ;Get byte INC BP ;Point to next MOV BL,08 ;8 bits MOV DI,013C ;Destination MOV BYTE PTR [DI],00 ;Zero it out RCL DH,1 ;Get the bit ADC BYTE PTR [DI],30 ;Put in 0 or 1 INC DI ;Next bit DEC BL ;Bit counter JNZ 0116 ;Loop around MOV DX,0139 ;Point to output MOV AH,09 ;And print it INT 21 DEC BH ;Bytes per character JNZ 010C ;Loop around MOV DX,0145 ;Print out return MOV AH,09 INT 21 LOOP 010A ;Get next character INT 20 DB "DB 01234567b",0D,0A,"$" R CX 48 W Q If you simply execute: font2db you'll get a listing of the font on your screen. By redirecting standard output: FONT2DB > MYFONT the font will be saved in a file called MYFONT. Now you can load MYFONT into your text editor, turn off insert mode, and make changes to the font by replacing 0s with 1s where you want a dot, and 1s with 0s where you don't want a dot. To change the font height, simply delete or add lines. You can use from 1 to 32 lines per character, but make sure each character has the same number of bytes, or your font will look quite strange. After you've created your own font, the next step requires the IBM or Microsoft Macro Assembler. The shell program FONTLOAD.ASM is shown below. The INCLUDE statement includes your edited font in the assembly. For more versatility, you may want to assemble your fonts independently and rewrite the loader program to load them from disk files. ; FONTLOAD.ASM -- Loads a customized font CSEG Segment Assume CS:CSEG, DS:CSEG, ES:CSEG Org 0100h Entry: Mov AX,1100h ;Load font Mov BH,0Eh ;Bytes/char Mov BL,00h ;Block Mov CX,0100h ;Number chars Mov DX,0000h ;Start char Mov BP,Offset Font ;Address Int 10h Int 20h Font Label Byte Include MYFONT ;Your font file name goes here CSEG EndS End Entry Introducing EGA Graphics Programming graphics on the EGA is no picnic. If you are interested in creating graphics applications for the EGA, you should seriously consider using a "virtual device interface," such as that found in Microsoft Windows or IBM's Graphics Development Toolkit. The Graphics Development Toolkit, for instance, contains routines that can be accessed from IBM Pascal, IBM FORTRAN, IBM BASIC compiler, or Lattice C (but not the BASIC interpreter). Also, both the BASICA interpreter in DOS 3.2 and Microsoft QuickBASIC 2.0 support EGA graphics. If you have lots of time to while away waiting for your screen to be painted, you could also use the BIOS for graphics. The EGA BIOS supports the same Read Dot and Write Dot function calls supported by the system board BIOS for the CGA. The only difference is that register BH must contain the video page. The BIOS Write Dot call is extremely slow, about 0.5 milliseconds per dot on a normal 4.77-MHz PC or XT, so it takes a little under 2 minutes to refresh an entire 640-by-350 screen in the simplest case. WRITEDOT.COM times this, so you can see for yourself how bad it is. WRITEDOT.SCR: N WRITEDOT.COM A 100 MOV AX,0010 ;Set video mode INT 10 ; to 16 SUB BH,BH ;Page 0 SUB DX,DX ;Row 0 SUB CX,CX ;Column 0 MOV AL,01 ;Blue MOV AH,0C ;Write Dot INT 10 INC CX ;Next Column CMP CX,0280 ;See if 640 JB 010B ;If below, loop INC DX ;Next Row CMP DX,015E ;See if 350 JB 0109 ;If below, loop MOV AX,0003 ;Set video mode INT 10 ; to 3 INT 20 ;Terminate R CX 26 W Q If none of these methods is good enough and you want to program your own graphics, you'll be writing directly to the video memory and programming the EGA registers. There is no better way to learn EGA graphics than to dig into the EGA Technical Reference and sweat it out. You'll get the fastest graphics routines by programming in assembly language. You can also program EGA graphics routines directly in any high-level language that supports BIOS calls, register output commands, and direct access of memory in a far segment. Probably the best high-level language for programming EGA graphics is C, and that is what is used in the EGADEMO.C program. This program assumes your EGA is connected to an Enhanced Color Display. EGADEMO sets the video mode to 16, displays 100 random rectangles on your screen, sets the video mode to 16 again, and displays another 100 random rectangles by XORing (eXclusive ORing with the colors already on the screen). It then sets the video mode back to 3. EGADEMO was written for Microsoft C version 3. Library functions that correspond to int86 and outp may be different for other C compilers, and so also may be the use of a far pointer for directly accessing the screen. /* EGADEMO.C -- Compile with Microsoft C version 3 with /Ze parameter to enable "far" keyword. Programmed by C. Petzold. */ #include #define MAXROWS 350 #define MAXCOLS 640 #define COLBYTES MAXCOLS/8 #define GRAFOUT(index,value) { outp(0x3CE,index) ; outp(0x3CF,value) ; } #define SWAP(a,b,temp) { temp = a ; a = b ; b = temp ;} main() { setvideomode(16) ; randomrect(0) ; /* Draw colored rectangles */ setvideomode(16) ; randomrect(0x18) ; /* Rectangles with XORing */ setvideomode(3) ; } setvideomode(mode) /* Sets video mode */ int mode ; { union REGS regs ; regs.x.ax = mode ; int86(0x10, ®s, ®s) ; } randomrect(fnct) /* Draws 100 rectangles */ int fnct ; { unsigned int i, r1, c1, r2, c2, temp ; GRAFOUT(3,fnct) ; /* Function Register */ for ( i = 0 ; i < 100 ; i++) { r1 = rand() % MAXROWS ; r2 = rand() % MAXROWS ; c1 = rand() % MAXCOLS ; c2 = rand() % MAXCOLS ; if (r1 > r2) SWAP (r1, r2, temp) ; if (c1 > c2) SWAP (c1, c2, temp) ; rect(r1, c1, r2, c2, rand()%16); } } rect(r1, c1, r2, c2, color) /* r1 <= r2 and c1 <= c2 */ unsigned int r1, c1, r2, cs, color ; { char far *addr = (char far *) (0xA0000000L + COLBYTES*r1 + (c1>>3)) ; int numrows = r2 - r1 ; /* Number of rows */ int numcols = (c2 >> 3) - (c1 >> 3) - 1; /* Number of columns */ char lmask = 0xFF >> (c1 & 7) ; /* Mask for left */ char rmask = ~(0xFF >> (c2 & 7)) ; /* Mask for right */ register row, col ; if (numcols < 0) { /* Adjustment for small rows */ lmask &= rmask ; rmask = numcols = 0 ; } GRAFOUT(0, color) ; /* Set/Reset Register */ GRAFOUT(1, 0x0F) ; /* Enable Set/Reset Register */ for (row = 0 ; row < numrows ; row++) { GRAFOUT(8, lmask) ; /* Bit Mask Register */ *(addr++) &= 1 ; /* Left side */ GRAFOUT(8, 0xFF) ; for (col = 0 ; col < numcols ; col++) *(addr++) &= 1 ; /* Middle part */ GRAFOUT(8, rmask) ; *(addr++) &= 1 ; /* Right side */ addr += COLBYTES - 2 - numcols ; /* Next row */ } GRAFOUT(0, 0) ; /* Set/Reset to normal */ GRAFOUT(1, 0) ; /* S/R Enable to normal */ GRAFOUT(8, 0xFF) ; /* Bit mask to normal */ } With Microsoft C, version 3.00, the program can be compiled thus: MSC EGADEMO /Ze; LINK EGADEMO; The /Ze parameter is necessary to enable the bold far keyword. Graphics Memory Organization When you program graphics on the EGA, you'll be writing directly to the screen memory. This memory is organized differently from the memory in CGA graphics modes. In the CGA-compatible graphics modes (4 through 6), the display memory occupies 16K, beginning at segment address B800h. In medium- resolution modes (4 and 5), the 320 dots of each scan line require 80 bytes. Each byte represents 4 pixels with 2 bits each for the four colors. In high-resolution black-and-white mode 6, the 640 horizontal dots also require 80 bytes, each byte representing 8 pixels. In either case, 16,000 bytes are required for the 200 scan lines. The only complication is that all the even scan lines are at the top of this memory, followed by all the odd scan lines. The display memory in EGA graphics modes 13 through 16 occupies the 64K segment beginning at segment address A000h. In graphics mode 16 (350 scan lines with 640 dots each and 16 colors), one screen's worth of data requires 80 bytes per scan line times 350 scan lines times 4 (for the 16 colors), or 111,200 bytes. Two video pages are available, bringing total memory to 224,000 -- just below the maximum 256K on the EGA. This 256K of display memory fits into a 64K memory space by being organized into four 64K color planes. The four color planes represent the blue, red, green, and intensity bits that define the 16 colors. Each of the four color planes is addressed the same way. You specify what color plane you want to write to or read from by using the EGA registers accessible through output ports. The byte at address A000:0000 is the leftmost 8 bits in the first scan line of the display. The byte at address A000:0001 is the next 8 bits in the top scan line. For graphics modes 14 through 16, the byte at address A000:0050 is the first 8 bits in the second scan line. For graphics mode 13, the second scan line begins at address A000:0028. The most significant bit always represents the leftmost dot. Although the division of EGA graphics memory into identically addressed color planes initially appears clumsy, it has some distinct advantages. Since you can write to all four color planes simultaneously you can actually write up to 32 bits of data (8 bits of four colors) by writing 1 byte to the display memory. Partially for this reason, the wrong way to program the EGA graphics is to start off with a simple "Write Dot" routine and base all other graphics routines on this one function. You'll get much better speed if you try to take advantage of the EGA's memory organization rather than work against it. How EGADEMO Works EGADEMO illustrates the use of four of the EGA's graphics registers. Programming these registers correctly is necessary before you write graphics information to the display memory. These use the GRAFOUT macro. In each case an index value is first written to output port 3CE. This defines which register we want to write to. Next, the value we want to write to that register is written to output port 3CF. Other EGA registers have different port address and work differently. The first use of these registers is in the randomrect. The value written to the Function Register (with the index equal to 3) tells the EGA whether any data written to the display will be written without modification or will be ANDed, ORed, or XORed with the data already there. EGADEMO draws 100 rectangles without modification and 100 more with XORing. You can also program this register to rotate data being written to the display. The rect function programs the Set/Reset Register with the color of the rectangle and also programs the Set/Reset Enable Register to enable the set/reset function for all four color bits. This is not the only way to handle color on the EGA, but it is the most convenient for solid fills. The rect function also programs the Bit Mask Register. Since 1 byte of the EGA memory encompasses 8 horizontal pixels, you often need to protect some pixels from modification. Any bit in the Bit Mask Register set to 0 protects that bit from modification when you write to the display if that memory location has just been read. When you read a byte at a particular address from EGA memory, the contents of all four color planes at that address are latched internally in the EGA hardware. This is a total of 32 bits, 8 in each color plane. When you write a byte at an address, either the contents of these latches are written back to memory if the corresponding Bit Mask Register bit is 0, or something else is if the bit is 1. In the rect function, the data written to each bit where the Bit Mask Register is set to 1 is the color value in the Set/Reset Register. The rect function uses the Bit Mask Register for the left and right sides of the rectangle. This allows for rectangles that may not start or end on a byte boundary, since we want to protect the data to the left and right of the rectangle. The C statement: *(addr++) &= 1 appears three times in the rect function: for the left side of the rectangle, the central part, and the right side. This statement looks as if it's ANDing the contents of the video memory with 1, but it's really not. All this statement has to do (besides increment the address when it's done) is read a byte to latch the internal EGA registers and then write a byte to write the Set/Reset color value to the unprotected bits. The value we actually read or write out makes no difference. All we have to do is perform a read and a write. This statement happens to do it very quickly. (Watch out for your compiler, however. Originally, a 0 at the right side of the expression above was used, but Microsoft's C compiler "optimized" the statement to write only a 0 to memory. That would be OK in most cases, but not for the EGA.) Using the EGA Set/Reset Register is not the only way to do this, but it does indicate some of the strangeness involved in programming graphics for the EGA. The Write Dot routine in the EGA BIOS uses a different (but no simpler) approach involving the Map Mask Register. Having these two examples in front of you will help when you start exploring the EGA registers. There is much in the EGA to explore without getting anywhere near graphics. While the EGA will help make the transition to graphics-based software more pleasant to us, it opens up more potential in character modes as well. - - - - - Using the EGA Feature Connector for a 120-Column Display (PC Magazine Vol 5 No 15 Sept 16, 1986 by C. Petzold) You've probably heard of people who replace the crystals in their PC ATs to make them run faster. Did you know you can do the same thing with your EGA? With a video adapter, however, faster doesn't mean faster. Instead, faster means more: more dots and a higher resolution. By using a faster crystal with your EGA, you can go beyond the normal 80-column display. For under $15, you can construct the EGA External Clock Board that will let your EGA produce 120 columns on the Enhanced Color Display (ECD). In the EGA video modes that use 350 scan lines, the dot clock and all timing signals are derived from a 16.257-MHz crystal on the EGA board. Since your ECD requires a horizontal sync rate of 21.85 kHz, the EGA uses this 16.256-MHz dot clock to generate 744 dots per scan line, or 93 characters. Eighty of these characters are used in the display, 10 of them occur during the horizontal retrace, and the 3 left over are for the virtually nonexistent border. If you replace the 16.257-MHz crystal with something faster, you can generate more dots -- and thus more characters -- while still maintaining the 21.85-kHz horizontal sync rate required by the monitor. With a 24-MHz crystal you can squeeze out 120 columns on the ECD. These extra columns, in combination with the 43-line mode, produce a total of 5160 displayable characters instead of the meager 2000 on the conventional PC display. What is really amazing (for IBM) is that doing something like this is entirely supported by the EGA hardware and BIOS. First, you don't need to actually replace the crystal on your EGA board with one of a higher frequency. The mysterious Feature Connector that is a part of every EGA can route an external dot clock to the EGA hardware. That's partly what the Feature Connector is designed for. Second, the EGA BIOS lets you set up an area in memory containing new video parameter values that the BIOS will load into the CRT Controller registers to provide the correct timings for the additional columns. Another register that the BIOS will load directs the EGA hardware to use the external crystal instead of the one on the board. How high can this external dot clock frequency be? Boards that use the Chips and Technologies EGA CHIP-Set with crystal oscillators up to 32 MHz have been tested. That makes a readable (but obviously tiny) 160-column display. The IBM EGA, however, starts having flicker problems when you go beyond 28 MHz, so you're limited to about 140 characters. EGA boards from the same manufacturer may also have different limits. Your own board may be limited to 26 MHz, or it could go even higher than 32 MHz. Once you have the EGA External Clock Board built, you can experiment. The example here uses a 24-MHz crystal for 120 columns on the ECD. (A similar technique can be used to create 120 columns on the Monochrome Display, but it presents software problems discussed later.) You can build the EGA External Clock Board with just four parts, three pieces of wire, a soldering iron, and wire clippers. A 24-MHz crystal oscillator, the same size and shape as the 16.257-MHz crystal oscillator already on your EGA board, attaches to 3 pins on the EGA Feature Connector. Pins 32 and 31 provide 5 volts and ground, respectively, to power the oscillator. The 24-MHz output from the crystal oscillator connects to pin 28 of the Feature Connector. Besides a little hook-up wire (less than a foot) and a little solder, all four of the parts you'll need can be purchased from JDR Microdevices, 1224 S. Bascom Ave., San Jose, CA 95128; (800) 538-5000 or (800) 662-6279. The JDR prices and part numbers are: JDR Item No. Description Price ------------ ----------- ----- OSC24.0 24.0-MHz Xtal Oscillator $4.95 HDR-80 2 x 40 header strip (breakable) 2.49 P25x45 Proto Board/bare 2.5 x 4.5 inches 2.40 14 PIN ST 14-pin low-profile IC socket .11 Total $9.95 Add $2.50 UPS ground or $3.50 UPS air delivery Equivalents are available from many electronic supply houses. First cut the header strip (a knife will do it) so that you get a strip with 2 rows of 16 pins each. The long ends of the header strip will plug into the Feature Connector socket. Next, cut the perforated circuit board to about 1 1/2 inches by 2 inches. When you install the header strip on the circuit board, make sure the short pins go through the holes in the board so that the long pins can plug into the Feature Connector. Push the pins of the DIP socket through the holes from the other side of the board. If you're making a wire-wrap version, you can glue the header strip and DIP socket to the board and wire-wrap the pins. Otherwise, you simply have to cut three pieces of wire and solder one end of each piece to the pins on the DIP socket and the other end to the long pins of the header strip. Note that the wires connect to the header strip pins on the front of the board and connect to the DIP socket pins on the back of the board, so you'll have to run the wires from back to front through holes in the circuit board. When everything is soldered and secure, clip any excess leads from the header and DIP socket to about 1/4 inch. Plug the crystal oscillator into the DIP socket so that the text of the oscillator case is right side up when you hold the board with the header strip at the top. You may have to shorten the leads of the oscillator so it fits snugly into the socket. Remove your EGA board from your PC and plug the EGA External Clock Board into the Feature Connector so that it is parallel to the EGA board. Put the EGA board back into the PC. Just be careful to make sure that the case of the crystal oscillator doesn't short out any contacts on the board adjacent to it. If it threatens to, just slip in an index card to separate the two boards. The EGA BIOS recognizes only four text modes (0 through 3) when the EGA is attached to an ECD. Although mode 0 is normally a 40-column mode that is not used by most programs, we can redefine mode 0 so it uses the external crystal oscillator instead of the on-board crystal oscillator. If we store new values to be loaded into the CRT Controller registers, the EGA will display 120 columns when it is switched to video mode 0. 120COLS.COM provides the required software support for the EGA External Clock Board. You need only run the program once during your PC session, so you can put it in your AUTOEXEC.BAT file. Nothing will happen when you first run it. But now, try switching to video mode 0. You can do this either by executing: EGAMODE 0 or by executing: MODE BW40 with the regular DOS MODE command. Your screen will now switch to a 120-column by 25-line display. To get back to normal, use: EGAMODE 3 or MODE CO80 While in 120-column mode, you can also run EGA43.COM to display 43 lines of 120 columns each. 120COLS.SCR: N 120COLS.COM A 100 CLD SUB AX,AX MOV ES,AX ES: LDS SI,[04A8] ;Get SAV_PTR ES: MOV WORD PTR [04A8],016C ;Make it point here ES: MOV [04AA],CS PUSH CS POP ES MOV DI,016C ;Move addresses MOV CX,001C REPZ MOVSB ES: LDS SI,[016C] ;Get parameter ptr MOV DI,0188 MOV CX,05C0 REPZ ;Copy parameters MOVSB PUSH CS POP DS MOV WORD PTR [016C],0188 MOV [016E],CS MOV SI,0149 ;Put new values in MOV DI,0648 MOV CX,0023 REPZ MOVSB MOV DX,0748 ;Remain resident INT 27 ;New values follow DB 78,18,0E DW 1800 DB 01,03,00,03 DB AB DB 87,77,7D,22,78,27 DB 6C,1F,00,0D,06,07 DB 00,00,00,00,5E,2B DB 5D,3C,0F,5E,0A,A3 DB FF R CX 6C W Q You'll find that you can use DOS in 120-column mode, but pop-up utilities and applications programs may act oddly. In a perfect world, programs would determine the current dimensions of the screen from the BIOS and use those values, but you'll probably find that most programs just assume the screen is 80 columns wide. If these programs write to the screen through the BIOS, they will occupy only the left two-thirds of the display. If they write directly to the display memory, the beginning of the second row of text will start at column 81 of the first row on the screen and wrap around to the second row, and so on. This is too bad. When 120COLS has been loaded and video mode 0 is set, the EGA BIOS correctly sets up all the variables in the BIOS data area for other programs to use. Most PC programs, however, are "too smart" to use these variables. The problem with doing something similar for an EGA connected to the Monochrome Display is this: the Monochrome Display has only one text mode, which is video mode 7. You won't want to redefine mode 7 to 120 columns, because then you will no longer have an 80-column monochrome mode. Any program that writes directly to the screen will almost certainly have problems with 120 columns. WordStar can be patched to produce a 43-line display. You can also patch WordStar for 120 columns with or without a 43-line display. While this display isn't very useful for normal word processing, it's a real dream for program development in C or Pascal or any other languages that use nested loops. If you plan to use 120 columns in DOS, you need only patch offset 249h in WS.COM to 78h to tell WordStar to use 120 columns. Or you can use DOS as you normally would and have WordStar switch to 120-column mode. WS120.COM saves the video mode on entry and switches to video mode 0. On exit, it switches back to the original video mode. You must run 120COLS.COM during your PC session for this new version of WordStar to work properly. Put WS120.SCR on the same disk with WordStar's WS.COM and DEBUG.COM and execute: DEBUG < WS120.SCR to create a new version of WordStar WS.COM called WS120.COM. WS120.SCR: N WS.COM L N WS120.COM E 249 78 A 2A4 JMP 2E1 NOP JMP 300 A 2E1 MOV AH,0F INT 10 MOV [2E0],AL MOV AX,0000 INT 10 RET A 300 MOV AL,[2E0] SUB AH,AH INT 10 RET W Q WS43X120.COM uses 43 lines of 120 columns. Put WS43X120.SCR on the same disk with WordStar's WS.COM and DEBUG.COM and execute: DEBUG < WS43X120.SCR to create a new version of WS.COM called WS43X120.COM, which you can then rename to something shorter. WS43X120.SCR: N WS.COM L N WS43X120.COM E 248 2A E 249 78 A 2A4 JMP 2E1 NOP JMP 300 A 2E1 MOV AH,0F INT 10 MOV [2E0],AL MOV AX,0000 INT 10 SUB BL,BL MOV AX,1112 INT 10 MOV CX,0007 MOV AH,1 INT 10 RET A 300 MOV AL,[2E0] SUB AH,AH INT 10 RET W Q Since we've socketed the crystal oscillator on the EGA External Clock Board, you can try out different frequencies by substituting different crystal oscillators. To develop the corresponding software support, you'll need the EGA Technical Reference to learn about the organization of the video parameters and the programming of the CRT Controller registers. Use 120COLS.COM as an example. Readers familiar with digital logic circuitry might look at another aspect of the Feature Connector. Pins 20 and 21 are signals you can control from software using the Feature Control Register. You could put four different crystals and a 74153 multiplexer chip on an external board and select which crystal to use by programming this register. If you have a NEC JC-1401P3A Multisync monitor, you have even more options. The Multisync is not limited to a horizontal sync rate of 21.85 kHz, so you can use a higher crystal frequency to increase the number of scan lines as well as the number of dots per line. However, some code in the EGA BIOS, particularly that which recalculates EGA register values based on different font heights, always assumes 200 or 350 scan lines, so using more scan lines may not be easy. In any event, it is clear that by using the Feature Connector to expand the capabilities of the EGA, the board becomes more powerful than anyone has yet suspected.