; Source name : INFO.ASM ; Executable name : INFO.COM ; Code model: : Real mode flat model ; Version : 2.0 ; Created date : 9/18/1999 ; Last update : 9/19/1999 ; Author : Jeff Duntemann ; Description : A utility to query and display information about ; the installed PC video adapter, programmed for ; real mode flat model, using NASM 0.98 and ALINK. ; This program demonstrates how lookup tables and ; numerous instructions are used. [BITS 16] ; Set 16 bit code generation [ORG 0100H] ; Set code start address to 100h (COM file) [SECTION .text] ; Section containing code %include "MYLIB.MAC" ; Load in screen control macro library START: ; This is where program execution begins: call VidCheck ; Initialize all video information variables Clear VidSegment,ClearAtom,VidBufSize ; Clear the screen ; Here we display the name of the program and its author: Writeln IDString,LIDString ; Display the program name Writeln AuthorStr,LAuthorStr ; display the author name Newline ; Here we display the name of the installed video board: Write VidIDStr,LVidIDStr ; Display the intro string mov BX,1 ; Select DOS file handle 1: Standard Output mov CX,27 ; The name strings are 27 bytes long mov DX,[BordName]; The string address is stored in BordName mov AH,40H ; Service 40H: Write string to file int 21H ; Call DOS to display to Standard Output Newline ; Here we display the segment address of the refresh buffer: Write OrgIDStr,LOrgIDStr ; Display the intro string mov AX,[VidSegment] ; AX gets the value to convert to a string mov SI,DigitStr ; String equivalent is written to DigitStr call Word2Str ; Do the actual string conversion PokeChar DigitStr,'H',4 ; Append 'H' on the end of the string Writeln DigitStr,5 ; and display the string equivalent ; Here we display the size of the current text font: Write FontSzStr,LFontSzStr ; Display the intro string mov AL,[FontSize] ; AL gets the value to convert to a string mov SI,DigitStr ; String equivalent is written to DigitStr call Byte2Str ; Do the actual string conversion PokeChar DigitStr,'H',2 ; Append 'H' on the end of the string Writeln DigitStr,3 ; and display the string equivalent ; Here we display the number of lines on the screen: Write ScrnLnStr,LScrnLnStr mov AL,[VisibleY] ; AL gets the value to convert to a string mov SI,DigitStr ; String equivalent is written to DigitStr call Byte2Str ; Do the actual string conversion PokeChar DigitStr,'H',2 ; Append 'H' on the end of the string Writeln DigitStr,3 ; and display the string equivalent ;Finally, we display the size of the video refresh buffer: Write BufSizStr,LBufSizStr ; Display the intro string mov AX,[VidBufSize] ; AX gets the value to convert to a string mov SI,DigitStr ; String equivalent is written to DigitStr call Word2Str ; Do the actual string conversion PokeChar DigitStr,'H',4 ; Append 'H' on the end of the string Writeln DigitStr,5 ; and display the string equivalent Newline mov AH,4CH ; Terminate process DOS service mov AL,0 ; Pass this value back to ERRORLEVEL int 21H ; Control returns to DOS ;--------------------------------------------------------------- ; Byte2Str -- Converts a byte passed in AL to a string at ; DS:SI ; Last update 9/18/99 ; ; 1 entry point: ; ; Byte2Str: ; Caller must pass: ; AL : Byte to be converted ; DS : Segment of destination string ; SI : Offset of destination string ; ; This routine converts 8-bit values to 2-digit hexadecimal ; string representations at DS:SI. ;--------------------------------------------------------------- Byte2Str: mov DI,AX ; Duplicate byte in DI and DI,000FH ; Mask out high 12 bits of DI mov BX,Digits ; Load offset of Digits into DI mov AH,BYTE [BX+DI] ; Load digit from table into AH mov [SI+1],AH ; and store digit into string xor AH,AH ; Zero out AH mov DI,AX ; And move byte into DI ; shr DI,4 ; This can do the four shifts on 286 and later shr DI,1 ; Shift high nybble of byte to shr DI,1 ; low nybble shr DI,1 shr DI,1 mov AH,BYTE [BX+DI] ; Load digit from table into AH mov [SI],AH ; and store digit into string ret ; We're done--go home! ;--------------------------------------------------------------- ; Word2Str -- Converts a word passed in AX to a string at ; DS:SI ; Last update 9/19/99 ; ; 1 entry point: ; ; Word2Str: ; Caller must pass: ; AX : Word value (16 bits) to be converted ; DS : Segment of destination string ; SI : Offset of destination string ;--------------------------------------------------------------- Word2Str: mov CX,AX ; Save a copy of convertee in CX xchg AH,AL ; Swap high and low AX bytes to do high first call Byte2Str ; Convert AL to string at DS:SI add SI,2 ; Bump SI to point to second 2 characters mov AX,CX ; Reload convertee into AX call Byte2Str ; Convert AL to string at DS:SI ret ; And we're done! ;--------------------------------------------------------------- ; VidCheck -- Identifies display board & display parameters ; Last update 9/18/99 ; ; 1 entry point: ; ; VidCheck: ; Caller need pass no parameters. ; VidCheck identifies the installed display board by ; calling DispID. It then calculates numerous display ; information values, which it then stores in the block ; of display information variables in the data segment. ;--------------------------------------------------------------- VidCheck: ; First task is to figure out which board is on the bus: call DispID ; Ask BIOS for adapter code; returns in AL mov [DispType],AL ; Store display adapter code in DispType ; Next we determine the font size currently in force: cmp AL,0AH ; See if board is an MCGA jl TryOld ; If less than code 0AH, it's not an MCGA mov [FontSize],BYTE 16 ; MCGA supports *only* 16 pixel text font jmp GetName ; Jump ahead to look up adapter name string TryOld: cmp [DispType],BYTE 01 ; Is the display adapter code 1, for MDA? jne TryCGA ; If not, go test for CGA code 2 mov [FontSize],BYTE 14 ; MDA uses *only* 14-pixel text font jmp GetName ; Jump ahead to look up adapter name string TryCGA: cmp [DispType],BYTE 02 ; Is the display adapter code 2, for CGA? jne TryVGA ; If not, go test for EGA/VGA font size mov [FontSize],BYTE 08 ; CGA uses *only* 8-pixel text font jmp GetName ; Jump ahead to look up adapter name string TryVGA: mov AH,11H ; Select VIDEO Get Font Information subservice mov AL,30H ; requires AH = 11H and AL = 30H mov BH,0 ; 0 = Get info about current font int 10H ; Call VIDEO mov [FontSize],CL ; Font size in pixels is returned in CL ; Next we get the name string for the board from the info table: GetName: mov AL,[DispType] ; Load display adapter code into AL xor AH,AH ; Zero AH so we don't copy trash into DI mov DI,AX ; Copy AX (with code in AL) into DI mov CL,5 ; We must shift the code 5 bits to mult. by 32 shl DI,CL ; Multiply code by 32 to act as table index mov BX,VidInfoTbl ; Load address of origin table into BX mov [BordName],BX ; Save pointer to video info. table in BordName add [BordName],DI ; Add offset into table to right element ; Next we get the refresh buffer segment from the table: mov AX,[BX+DI+27] ; Index into table past name string to segment mov [VidSegment],AX ; Store segment from table to VidSegment variable ; Here we calculate the number of lines on-screen from font size: xor AH,AH ; Make sure AH has no trash in it mov AL,[FontSize] ; Load the font size in pixels into AL cmp AL,8 ; Is it the 8-pixel font? jne Try14 ; If not, try the 14-pixel font mov AL,1 ; The 8-pixel font is table offset 1 jmp ReadLns ; Jump ahead to read screen lines from table Try14: cmp AL,14 ; Is it the 14-pixel font? jne Do16 ; If not, it has to be the 16-pixel font mov AL,2 ; The 14-pixel font is table offset 2 jmp ReadLns ; Jump ahead to read screen lines from table Do16: mov AL,3 ; The 16-pixel font is table offset 3 ReadLns: add DI,AX ; Add font size offset to table element offset mov AL,[BX+DI+28] ; Load the screen lines value from the table mov [VisibleY],AL ; and store it in the VisibleY variable mov AH,[VisibleX] ; Load the screen columns value to AH xchg AH,AL ; Exchange AH & AL for 0-basing dec AL ; Subtract one from column count for 0-basing dec AH ; Subtract one from line count for zero-basing mov [LRXY],AX ; And store 0-based X,Y word into LRXY variable ; Finally, we calculate the size of the refresh buffer in bytes: mov AL,[VisibleY] ; We multiply screen lines time screen columns mul BYTE [VisibleX] ; times 2 (for attributes) to get buffer size shl AX,1 ; Multiply lines * columns by 2 mov [VidBufSize],AX ; Store refresh buffer size in VidBufSize ret ; Return to caller ;--------------------------------------------------------------- ; DispID -- Identifies the installed display adapter ; Last update 9/18/99 ; ; 1 entry point: ; ; DispID: ; Caller passes no parameters ; Routine returns a code value in AX. ; The codes are these: ; 0 : Adapter is unknown; recommend aborting ; 1 : MDA (Monochrome Display Adapter) ; 2 : CGA (Color Graphics Adapter) ; ;--------------------------------------------------------------- DispID: mov AH,1AH ; Select PS/2 Identify Adapter Service xor AL,AL ; Select Get Combination Code Subservice (AL=0) int 10H ; Call VIDEO cmp AL,1AH ; If AL comes back with 1AH, we have a PS/2 jne TryEGA ; If not, jump down to test for the EGA mov AL,BL ; Put Combination Code into AL ret ; and go home! TryEGA: mov AH,12H ; Select EGA Alternate Function mov BX,10H ; Select Get Configuration Information subservice int 10H ; Call VIDEO cmp BX,10H ; If BX comes back unchanged, EGA is *not* there je OldBords ; Go see whether it's an MDA or CGA cmp BH,0 ; If BH = 0, it's an EGA/color combo je EGAColor ; otherwise it's EGA/mono mov AL,5 ; Store code 5 for EGA mono ret ; and go home! EGAColor: mov AL,4 ; Store code 4 for EGA color ret ; and go home! OldBords: int 11H ; Call Equipment Configuration interrupt and AL,30H ; Mask out all but bits 4 & 5 cmp AL,30H ; If bits 4 & 5 are both =1, it's an MDA jne CGA ; otherwise it's a CGA mov AL,1 ; Store code 1 for MDA ret ; and go home! CGA: mov AL,2 ; Store code 2 for CGA ret ; and go home! [SECTION .data] ;--------------------------------------------------------------- ; DISPLAY INFORMATION VARIABLES ; ; The following block of variables all relate to the video ; system and are initialized by the VidCheck procedure: ;--------------------------------------------------------------- DispType DB 0 ; Code for display adapter type VidSegment DW 0B000H ; Segment of installed display buffer VidOrigin DW 0 ; Offset for FAR pointer to refresh buffer VisibleX DB 80 ; Number of columns on screen VisibleY DB 25 ; Number of lines on screen VidBufSize DW 4000 ; Default to 25 X 80 X 2 (char & attribute) FontSize DB 8 ; Either 8, 14, or 16; default to 8 BordName DW 0 ; NEAR pointer to name string of installed board ; 18H = 24D; 4FH = 79D; Combined 0-based X,Y of 80 x 25 screen LR corner: LRXY DW 184FH ;--------------------------------------------------------------- ; DISPLAY ADAPTER INFORMATION LOOKUP TABLE ; ; This is the lookup table containing information on all legal ; display adapters. The first field in each element is a 26- ; character string containing a brief description of the ; adapter. The next field is the segment of the video refresh ; buffer. The last three fields are the number of screen lines ; an adapter displays when the 8-pixel, 14-pixel, and 16-pixel ; fonts are loaded, respectively. Note that not all adapters ; support all fonts, but a screen line count is given for all ; three fonts for all adapter types. Illegal combinations will ; not be accessed. ;--------------------------------------------------------------- VidInfoTbl DB 'No adapter identified ' ; Code 0 DW 0B000H DB 25,25,25 DB 'Monochrome Display Adapter ' ; Code 1 DW 0B000H DB 25,25,25 DB 'Color Graphics Adapter ' ; Code 2 DW 0B800H DB 25,25,25 DB 'Code 3: Undefined ' ; Code 3 DW 0B000H DB 25,25,25 DB 'EGA with color monitor ' ; Code 4 DW 0B800H DB 43,25,25 DB 'EGA with mono monitor ' ; Code 5 DW 0B000H DB 43,25,25 DB 'Code 6: Undefined ' ; Code 6 DW 0B000H DB 25,25,25 DB 'VGA with mono monitor ' ; Code 7 DW 0B000H DB 50,27,25 DB 'VGA with color monitor ' ; Code 8 DW 0B800H DB 50,27,25 DB 'Code 9: Undefined ' ; Code 9 DW 0B000H DB 25,25,25 DB 'MCGA with digital color ' ; Code 0AH DW 0B800H DB 25,25,25 DB 'MCGA with monochrome ' ; Code 0BH DW 0B000H DB 25,25,25 DB 'MCGA with analog color ' ; Code 0CH DW 0B800H DB 25,25,25 Digits DB '0123456789ABCDEF' ; Lookup table for numeric/string conv. ;--------------------------------------------------------------- ; These two variables are screen-clear "atoms" useable by the ; Clear macro. The high byte is the display attribute, while ; the low byte is the character with which Clear fills the ; video refresh buffer to clear the screen. ;--------------------------------------------------------------- HToneAtom DW 07B0H ; Clears screen to halftone pattern ClearAtom DW 0720H ; Clears screen to blanks ;--------------------------------------------------------------- ; This is where all predefined string variables are stored. ;--------------------------------------------------------------- CRLF DB 0DH,0AH ; Newline string IDString DB '>>>INFO V2.0' LIDString EQU $-IDString AuthorStr DB ' by Jeff Duntemann K7JPD' LAuthorStr EQU $-AuthorStr VidIDStr DB ' The installed video board is: ' LVidIDStr EQU $-VidIDStr OrgIDStr DB ' The segment of the video refresh buffer is: ' LOrgIDStr EQU $-OrgIDStr FontSzStr DB ' The size of the current text font is: ' LFontSzStr EQU $-FontSzStr ScrnLnStr DB ' The number of lines currently on the screen is: ' LScrnLnStr EQU $-ScrnLnStr BufSizStr DB ' The size of the refresh buffer in bytes is: ' LBufSizStr EQU $-BufSizStr DigitStr DB ' ' LDigitStr EQU $-DigitStr