home *** CD-ROM | disk | FTP | other *** search
- ;****************************************************************************
- ; UMASCAN scans the PC's address space from 640K to 1MB and lists the ROM,
- ; RAM, Video RAM, EMS pages, and unused areas that it finds. Its syntax is:
- ;
- ; UMASCAN [/M]
- ;
- ; where /M forces it to run in monochrome mode (useful on laptops). The
- ; ROM it reports may be adapter ROM or system ROM. The RAM it reports may
- ; be adapter RAM or UMB RAM. Any unused areas it identifies are candidates
- ; to be converted to UMBs using DOS's EMM386.EXE driver.
- ;****************************************************************************
-
- code segment
- assume cs:code,ds:code
- org 100h
- begin: jmp main
-
- header1 db "UMASCAN 1.1 Copyright (c) 1993 Jeff Prosise",0
- header2 db "From: PC Magazine DOS 6 Memory Management with "
- db "Utilities",0
-
- helpmsg db "Draws a map profiling the upper memory area and "
- db "identifies unused",13,10
- db "address space that may be converted to upper memory "
- db "blocks.",13,10,13,10
- db "UMASCAN [/M]",13,10,13,10
- db " /M Use monochrome video attributes.",13,10,13,10
- db "Run UMASCAN when EMM386.EXE is not loaded to "
- db "identify adapter RAM.",13,10,"$"
-
- errmsg1 db "Syntax: UMASCAN [/M]",13,10,"$"
-
- map db 192 dup (32) ;Upper memory map
-
- colors label byte ;Color video attributes
- border_color db 1Fh
- back_color db 3Fh
- fore_color db 1Fh
- rom_color db 5Bh
- ram_color db 4Fh
- video_color db 2Eh
- ems_color db 3Fh
- unk_color db 7Fh
- note_color db 07h
- title_color db 0Fh
- shadow_color db 07h
-
- mono_colors db 70h,07h,7Fh,0Fh,0Fh,0Fh ;Monochrome attributes
- db 0Fh,0Fh,07h,0Fh,07h
-
- devname db "EMMXXXX0" ;EMM device name
- video_segment dw 0B800h ;Current video segment
- video_offset dw ? ;Video buffer start address
- line_length dw ? ;Bytes per video line
- maxrow db 24 ;Highest row number
-
- text1 db "F000",0
- text2 db "E000",0
- text3 db "D000",0
- text4 db "C000",0
- text5 db "B000",0
- text6 db "A000",0
-
- text7 db 0Ah,"0",0Ch,"1",0Eh,"2",10h,"3"
- db 13h,"4",15h,"5",17h,"6",19h,"7"
- db 1Ch,"8",1Eh,"9",20h,"A",22h,"B"
- db 25h,"C",27h,"D",29h,"E",2Bh,"F"
-
- text8 db " LEGEND ",0
- text9 db "RRRR",0
- text10 db "++++",0
- text11 db "VVVV",0
- text12 db "EEEE",0
- text12x db "UUUU",0
- text13 db "ROM",0
- text14 db "RAM",0
- text15 db "Video Buffer",0
- text16 db "EMS Page Frame",0
- text17 db "Unknown",0
-
- text18 db "1. RRRR indicates adapter ROM or system board "
- db "ROM.",0
- text19 db "2. ++++ indicates adapter RAM or UMB RAM created by "
- db "a 386 memory manager.",0
- text20 db "3. Areas marked UUUU usually contain a mixture of "
- db "ROM, RAM, and unused space.",0
- text21 db " These areas generally should not be converted to "
- db "upper memory blocks.",0
- text22 db "4. Unmarked areas may safely be converted to upper "
- db "memory blocks.",0
-
- text23 db " Press Esc to exit ",0
-
- ;****************************************************************************
- ; Procedure MAIN
- ;****************************************************************************
-
- main proc near
- cld ;Clear direction flag
- mov si,81h ;Point SI to command line
- call scanhelp ;Scan for "/?" switch
- jnc main1 ;Branch if not found
-
- mov ah,09h ;Display help text and exit
- mov dx,offset helpmsg ;with ERRORLEVEL=0
- int 21h
- mov ax,4C00h
- int 21h
- ;
- ; Modify the color palette if a /M switch was included.
- ;
- main1: call findchar ;Advance to next character
- jc main3 ;Branch if there is none
- lodsw ;Get the next two characters
- and ah,0DFh ;Capitalize the second one
- cmp ax,4D2Fh ;Error if other than /M
- je main2
-
- mov ah,9 ;Display error message
- mov dx,offset errmsg1
- int 21h
- mov ax,4C01h ;Exit with ERRORLEVEL=1
- int 21h
-
- main2: call change_colors ;Change color palette to mono
- ;
- ; Draw the screen and terminate when a key is pressed.
- ;
- main3: call init_video ;Initialize video
- mov ah,03h ;Get the cursor type
- mov bh,00h ;from the BIOS
- int 10h
- push cx ;Save it
- mov ah,01h ;Hide the cursor
- mov ch,20h
- int 10h
-
- call draw_screen ;Paint the screen
- call build_table ;Build the map table
- call draw_map ;Display the memory map
-
- main4: mov ah,00h ;Pause until Esc is pressed
- int 16h
- cmp al,27
- jne main4
-
- call clear_screen ;Clear the screen
- mov ah,0Fh ;Get the active page number
- int 10h
- mov ah,02h ;Home the cursor to the upper
- mov dx,0000h ;left corner of the screen
- int 10h
- mov ah,01h ;Make the cursor visible
- pop cx ;again
- int 10h
- mov ax,4C00h ;Exit with ERRORLEVEL=0
- int 21h
- main endp
-
- ;****************************************************************************
- ; SCANHELP scans the command line for a /? switch. If found, carry returns
- ; set and SI contains its offset. If not found, carry returns clear.
- ;****************************************************************************
-
- scanhelp proc near
- push si ;Save SI
- scanloop: lodsb ;Get a character
- cmp al,0Dh ;Exit if end of line
- je scan_exit
- cmp al,"?" ;Loop if not "?"
- jne scanloop
- cmp byte ptr [si-2],"/" ;Loop if not "/"
- jne scanloop
-
- add sp,2 ;Clear the stack
- sub si,2 ;Adjust SI
- stc ;Set carry and exit
- ret
-
- scan_exit: pop si ;Restore SI
- clc ;Clear carry and exit
- ret
- scanhelp endp
-
- ;****************************************************************************
- ; FINDCHAR advances SI to the next non-white space character. On return,
- ; carry set indicates EOL was encountered; carry clear indicates it was not.
- ;****************************************************************************
-
- findchar proc near
- lodsb ;Get the next character
- cmp al,09h ;Loop if tab
- je findchar
- cmp al,20h ;Loop if space
- je findchar
- cmp al,2Ch ;Loop if comma
- je findchar
- dec si ;Point SI to the character
- cmp al,0Dh ;Exit with carry set if end
- je eol ;of line is reached
-
- clc ;Clear carry and exit
- ret
-
- eol: stc ;Set carry and exit
- ret
- findchar endp
-
- ;****************************************************************************
- ; CHANGE_COLORS copies monochrome attribute values to the color table.
- ; On entry, both DS and ES must point to the code segment.
- ;****************************************************************************
-
- change_colors proc near
- mov si,offset mono_colors
- mov di,offset colors
- mov cx,11
- rep movsb
- ret
- change_colors endp
-
- ;****************************************************************************
- ; INIT_VIDEO initializes the variables used by the program's video output
- ; routines and makes sure we're in an 80-column text mode.
- ;****************************************************************************
-
- init_video proc near
- mov ax,40h ;Point ES to the BIOS data
- mov es,ax ;area
-
- mov al,es:[49h] ;Get video mode in AL
- cmp al,0Fh ;Branch if it's other than
- jne init1 ;0Fh (EGA mono graphics)
- mov ax,0007h ;Switch to mode 7 (80-column
- int 10h ;monochrome text)
- jmp short init2 ;Branch and change colors
-
- init1: cmp al,7 ;Branch if it's other than
- jne init3 ;mode 7 (monochrome text)
- init2: mov ax,cs ;Point ES back to the code
- mov es,ax ;segment
- call change_colors ;Change color palette to mono
- mov ax,40h ;Point ES back to the BIOS
- mov es,ax ;data area
- mov video_segment,0B000h ;Change to monochrome segment
- jmp short init5 ;Branch past mode check
-
- init3: cmp al,2 ;Reset the video mode if the
- jb init4 ;current video mode number
- cmp al,3 ;is less than 2 or greater
- jbe init5 ;than 3
- init4: mov ax,0003h ;Switch to mode 3 (80-column
- int 10h ;color text)
-
- init5: mov ax,es:[4Ah] ;Get number of columns in AX
- shl ax,1 ;Compute bytes per video line
- mov line_length,ax ;Store it in LINE_LENGTH
-
- mov ax,es:[4Eh] ;Save the starting address
- mov video_offset,ax ;of the video buffer
-
- mov ax,1A00h ;Branch if the system
- int 10h ;contains a VGA video
- cmp al,1Ah ;adapter
- je init6
-
- mov ah,12h ;Branch if the system does
- mov bl,10h ;not contain an EGA video
- int 10h ;adapter
- cmp bl,10h
- je init7
-
- init6: mov al,es:[84h] ;Read the highest row number
- mov maxrow,al ;from the BIOS data area
- init7: ret
- init_video endp
-
- ;****************************************************************************
- ; BUILD_TABLE fills in the MAP array by performing a series of tests to
- ; determine what type of video hardware is installed, where physical EMS
- ; pages are located, and what regions of upper memory contain RAM and ROM.
- ;****************************************************************************
-
- build_table proc near
- mov ax,cs ;Point ES to the code
- mov es,ax ;segment
- ;
- ; Check for a VGA video adapter and fill in the A000 and B000 segments
- ; if a VGA is detected.
- ;
- mov ax,1A00h ;Check for a VGA by calling
- int 10h ;function 1A00h in the
- cmp al,1Ah ;video BIOS
- jne check_ega ;Branch if no VGA
- mov di,offset map ;Fill the first 64 bytes of
- mov al,"V" ;the MAP array with "V"s
- mov cx,64
- rep stosb
- jmp check_ems ;Branch to EMS check
- ;
- ; If there's an EGA installed, fill in the MAP array based on whether the
- ; EGA is attached to a monochrome or color monitor and how much video RAM
- ; it contains.
- ;
- check_ega: mov ah,12h ;Check for an EGA adapter
- mov bl,10h ;and branch if there's not
- int 10h ;one installed
- cmp bl,10h
- je check_cga
-
- mov ax,40h ;Point ES to the BIOS data
- mov es,ax ;area
- cmp byte ptr es:[49h],7 ;Branch if mode number is
- jne ega_color ;other than 7
-
- mov ax,cs ;Point ES back to the code
- mov es,ax ;segment
- mov di,offset map+32 ;For an EGA attached to a
- mov al,"V" ;monochrome monitor, fill
- mov cx,16 ;in B000 through B3FF if
- cmp bl,0 ;the EGA contains 64K of
- jne ega1 ;RAM, or B000 through
- mov cx,8 ;B7FF if there's more
- ega1: rep stosb ;than 64K on board
-
- mov di,offset map ;For an EGA attached to a
- mov al,"V" ;monochrome monitor, fill
- mov cx,32 ;in A000 through A7FF if
- cmp bl,0 ;the EGA contains 64K of
- jne ega2 ;RAM, or A000 through
- mov cx,16 ;AFFF if there's more
- ega2: rep stosb ;than 64K on board
- jmp short check_cga ;Check for a CGA, too
-
- ega_color: mov ax,cs ;Point ES back to the code
- mov es,ax ;segment
- mov di,offset map+48 ;For an EGA attached to a
- mov al,"V" ;color monitor, fill in
- mov cx,16 ;B800 through BBFF if the
- cmp bl,0 ;EGA contains 64K of RAM,
- jne ega3 ;or B800 through BFFF if
- mov cx,8 ;there's more than 64K
- ega3: rep stosb ;on board
-
- mov di,offset map ;For an EGA attached to a
- mov al,"V" ;color monitor, fill in
- mov cx,32 ;A000 through A7FF if the
- cmp bl,0 ;EGA contains 64K of RAM,
- jne ega4 ;or A000 through AFFF if
- mov cx,16 ;there's more than 64K
- ega4: rep stosb ;on board
- ;
- ; Check for a CGA, MDA, or Hercules card and fill the MAP array accordingly.
- ;
- check_cga: mov dx,3D4h ;Write a "V" to bytes 48
- call test_crtc ;through 55 of the MAP
- jc check_mda ;array if there's a
- mov di,offset map+48 ;CGA installed
- mov al,"V"
- mov cx,8
- rep stosb
-
- check_mda: mov dx,3B4h ;Write a "V" to bytes 32
- call test_crtc ;through 33 of the MAP
- jc check_ems ;array if there's an
- mov di,offset map+32 ;MDA installed
- mov al,"V"
- mov cx,2
- rep stosb
-
- mov dx,3BAh ;Determine if a Hercules
- in al,dx ;video adapter is installed
- mov ah,al ;by seeing if bit 7 of the
- and ah,80h ;CRTC's Status Register
- mov cx,8000h ;changes
- hgc1: in al,dx
- and al,80h
- cmp ah,al
- jne hgc2 ;Exit loop if value changed
- loop hgc1 ;Try again if it didn't
- jmp short check_ems ;Branch if test was negative
-
- hgc2: mov di,offset map+32 ;Fill the entire B000 area
- mov al,"V" ;of the MAP array with "V"s
- mov cx,32 ;if a Hercules adapter was
- rep stosb ;detected
- ;
- ; Check for the presence of an expanded memory manager (EMM) and locate
- ; the EMS page frame if an EMM is installed.
- ;
- check_ems: mov ax,3567h ;See if there is an EMM
- int 21h ;installed by checking
- mov di,10 ;for the string "EMMXXXX0"
- mov si,offset devname ;10 bytes past where the
- mov cx,8 ;interrupt 67h vector
- repe cmpsb ;points to
- jne check_arom ;Branch if no EMM detected
-
- mov ax,cs ;Point ES back to the code
- mov es,ax ;segment
- mov ah,40h ;Now make sure the EMM
- int 67h ;hardware is present
- cmp ah,00h ;and operational
- jne check_arom ;Branch if it's not
- ;
- ; Get EMS page frame information.
- ;
- mov ah,41h ;Determine segment address
- int 67h ;of the EMS page frame by
- cmp ah,00h ;calling function 41h
- jne check_arom
- cmp bx,0A000h ;Branch if page frame is
- jb check_arom ;below A000h
- sub bx,0A000h ;Compute corresponding
- mov cl,7 ;offset into MAP array
- shr bx,cl
- mov di,offset map
- add di,bx
- mov al,"E" ;Write "E" to 32 consecutive
- mov cx,32 ;blocks to identify the
- rep stosb ;page frame
- ;
- ; Check for adapter ROM by inspecting the first two bytes of every 2K
- ; block between segments C000 and F400 for an adapter ROM signature.
- ;
- check_arom: mov si,64 ;SI holds index into MAP
-
- arom1: cmp byte ptr [si+offset map],20h ;Skip this block if
- jne next_block ;already checked
-
- mov ax,si ;Compute next segment address
- mov cl,7 ;by shifting SI 7 bits left
- shl ax,cl ;and adding A000h
- add ax,0A000h
- mov es,ax ;Transfer result to ES
-
- cmp word ptr es:[0],0AA55h ;Branch if no signature is
- jne next_block ;found
-
- mov al,es:[2] ;Get number of blocks
- cbw ;Convert byte to word
- mov cl,9 ;Compute length of adapter
- shl ax,cl ;ROM in bytes
- mov cx,ax ;Transfer result to CX
- xor al,al ;Zero AL and DI
- xor di,di
-
- arom3: add al,es:[di] ;Validate the ROM by summing
- inc di ;all the bytes in it,
- loop arom3 ;modulo 100h
- or al,al ;Not a valid ROM module if
- jnz next_block ;the result isn't zero
-
- mov al,es:[2] ;Get number of blocks
- add al,3 ;Compute number of 2K
- shr al,1 ;blocks the module
- shr al,1 ;comprises
- mov cl,al ;Transfer result to CL
- xor ch,ch ;Byte to word in CX
- push cx ;Save the result
-
- mov ax,cs ;Write "R"s to affected
- mov es,ax ;areas of the MAP array
- mov di,si
- add di,offset map
- mov al,"R"
- rep stosb
-
- pop cx ;Retrieve block count
- add si,cx ;Add block count to SI
- dec si ;Decrement before proceeding
-
- next_block: cmp si,168 ;Increment SI and loop back
- jae check_ram ;if it's less than 168,
- inc si ;which corresponds to
- jmp arom1 ;segment F400
- ;
- ; Check all 2K blocks that haven't been analyzed yet for ROM or RAM.
- ;
- check_ram: call disable_nmi ;Disable NMI
-
- xor cx,cx ;Initialize counter
- mov dx,cs ;DX holds segment address
-
- ram1: push cx ;Save count
- mov si,cx ;Transfer count to SI
- cmp byte ptr [si+offset map],20h ;Skip this block if
- je ram2 ;already checked
- jmp next_region
-
- ram2: mov cl,7 ;Compute next segment address
- shl si,cl ;by shifting SI 7 bits left
- add si,0A000h ;and adding A000h
- mov bx,si ;Save result in BX
-
- mov ds,bx ;Copy the block to local
- assume ds:nothing ;memory
- xor si,si
- mov di,offset lastbyte
- mov es,dx
- mov cx,1024
- cli ;Interrupts off!!!
- rep movsw
- mov ds,dx
- assume ds:code
-
- mov es,bx ;Copy test data to the
- xor di,di ;block in upper memory
- mov si,0100h
- mov cx,1024
- rep movsw
-
- mov ds,bx ;Copy the block to local
- assume ds:nothing ;memory again
- xor si,si
- mov di,offset lastbyte+2048
- mov es,dx
- mov cx,1024
- rep movsw
- mov ds,dx
- assume ds:code
-
- mov es,bx ;Restore the block's
- xor di,di ;original contents
- mov si,offset lastbyte
- mov cx,1024
- rep movsw
- sti ;Interrupts on!!!
-
- mov si,0100h ;Compare what was written
- mov di,offset lastbyte+2048 ;to what was read back to
- mov es,dx ;determine if this block
- mov cx,1024 ;is populated with RAM
- repe cmpsw
- jne ram3 ;Branch if they're not equal
-
- pop si ;Retrieve count from stack
- push si ;Push it back on for later
- mov byte ptr [si+offset map],"+" ;Mark block as RAM
- jmp short next_region ;Branch and continue
-
- ram3: mov si,offset lastbyte ;Compare the two sets of
- mov di,offset lastbyte+2048 ;data read from the block
- mov cx,1024 ;to determine if the block
- repe cmpsw ;is populated with ROM
- jne ram4 ;Branch if they're not equal
-
- mov di,offset lastbyte ;See if all the bytes that
- mov al,[di] ;were read have the same
- mov cx,2048 ;value. If they do, then
- repe scasb ;this probably isn't ROM.
- je next_region
-
- pop si ;Retrieve count from stack
- push si ;Push it back on for later
- mov byte ptr [si+offset map],"R" ;Mark block as ROM
- jmp short next_region ;Branch and continue
-
- ram4: pop si ;Retrieve count from stack
- push si ;Push it back on for later
- mov byte ptr [si+offset map],"U" ;Mark block with "U"
-
- next_region: pop cx ;Retrieve count
- inc cx ;Increment count
- cmp cx,192 ;Loop until done
- je build_exit
- jmp ram1
-
- build_exit: call enable_nmi ;Enable NMI
- ret
- build_table endp
-
- ;****************************************************************************
- ; DISABLE_NMI disables NMI.
- ;****************************************************************************
-
- disable_nmi proc near
- mov ax,0C400h ;Find out if this is a PS/2
- int 15h
- jc dnmi1
-
- xor al,al ;Disable NMI on a PS/2
- out 70h,al
- jmp short $+2
- jmp short $+2
- in al,71h
- jmp short dnmi_exit
-
- dnmi1: in al,0A0h ;Disable NMI on a non-
- jmp short $+2 ;PS/2
- jmp short $+2
- and al,7Fh
- out 0A0h,al
- dnmi_exit: ret
- disable_nmi endp
-
- ;****************************************************************************
- ; ENABLE_NMI enables NMI.
- ;****************************************************************************
-
- enable_nmi proc near
- mov ax,0C400h ;Find out if this is a PS/2
- int 15h
- jc enmi1
-
- mov al,80h ;Enable NMI on a PS/2
- out 70h,al
- jmp short $+2
- jmp short $+2
- in al,71h
- jmp short enmi_exit
-
- enmi1: in al,0A0h ;Enable NMI on a non-
- jmp short $+2 ;PS/2
- jmp short $+2
- or al,80h
- out 0A0h,al
- enmi_exit: ret
- enable_nmi endp
-
- ;****************************************************************************
- ; DRAW_SCREEN paints the screen.
- ;****************************************************************************
-
- draw_screen proc near
- call clear_screen ;Clear the screen
-
- mov ah,title_color ;Write line 1 of the
- mov dx,0012h ;header at the top
- mov si,offset header1 ;of the screen
- call write_string
-
- mov ah,title_color ;Write line 2 of the
- mov dx,010Ch ;header
- mov si,offset header2
- call write_string
-
- mov ah,border_color ;Draw the border around
- mov cx,0300h ;the window at the top
- mov dx,104Fh ;of the screen
- call drawbox
-
- mov ax,0600h ;Clear the interior of
- mov bh,back_color ;the window
- mov cx,0401h
- mov dx,0F4Eh
- int 10h
-
- mov ax,0600h ;Draw the shadow behind
- mov bh,shadow_color ;the first subwindow
- mov cx,0605h
- mov dx,0E2Eh
- int 10h
-
- mov ax,0600h ;Draw the shadow behind
- mov bh,shadow_color ;the second subwindow
- mov cx,0635h
- mov dx,0E4Bh
- int 10h
-
- mov ax,0600h ;Draw the first subwindow
- mov bh,fore_color
- mov cx,0504h
- mov dx,0D2Dh
- int 10h
-
- mov ax,0600h ;Draw the second subwindow
- mov bh,fore_color
- mov cx,0534h
- mov dx,0D4Ah
- int 10h
-
- mov ah,fore_color ;Display segment addresses
- mov dx,0705h
- mov si,offset text1
- call write_string
-
- mov ah,fore_color
- mov dx,0805h
- mov si,offset text2
- call write_string
-
- mov ah,fore_color
- mov dx,0905h
- mov si,offset text3
- call write_string
-
- mov ah,fore_color
- mov dx,0A05h
- mov si,offset text4
- call write_string
-
- mov ah,fore_color
- mov dx,0B05h
- mov si,offset text5
- call write_string
-
- mov ah,fore_color
- mov dx,0C05h
- mov si,offset text6
- call write_string
-
- mov si,offset text7 ;Display "0" thru "F"
- mov cx,16 ;above the first
- dscr1: push cx ;subwindow
- lodsb
- mov dl,al
- mov dh,06h
- lodsb
- mov ah,fore_color
- call write_char
- pop cx
- loop dscr1
-
- mov ah,rom_color ;Display "LEGEND"
- mov dx,0635h
- mov si,offset text8
- call write_string
-
- mov ah,rom_color ;Display legend labels
- mov dx,0835h
- mov si,offset text9
- call write_string
-
- mov ah,ram_color
- mov dx,0935h
- mov si,offset text10
- call write_string
-
- mov ah,video_color
- mov dx,0A35h
- mov si,offset text11
- call write_string
-
- mov ah,ems_color
- mov dx,0B35h
- mov si,offset text12
- call write_string
-
- mov ah,unk_color
- mov dx,0C35h
- mov si,offset text12x
- call write_string
-
- mov ah,fore_color ;Display legend notes
- mov dx,083Bh
- mov si,offset text13
- call write_string
-
- mov ah,fore_color
- mov dx,093Bh
- mov si,offset text14
- call write_string
-
- mov ah,fore_color
- mov dx,0A3Bh
- mov si,offset text15
- call write_string
-
- mov ah,fore_color
- mov dx,0B3Bh
- mov si,offset text16
- call write_string
-
- mov ah,fore_color
- mov dx,0C3Bh
- mov si,offset text17
- call write_string
-
- mov ah,note_color ;Display notes at the
- mov dx,1200h ;bottom of the screen
- mov si,offset text18
- call write_string
-
- mov ah,note_color
- mov dx,1300h
- mov si,offset text19
- call write_string
-
- mov ah,note_color
- mov dx,1400h
- mov si,offset text20
- call write_string
-
- mov ah,note_color
- mov dx,1500h
- mov si,offset text21
- call write_string
-
- mov ah,note_color
- mov dx,1600h
- mov si,offset text22
- call write_string
-
- mov ah,rom_color ;Highlight text in the
- mov dx,1203h ;notes area
- mov si,offset text9
- call write_string
-
- mov ah,ram_color
- mov dx,1303h
- mov si,offset text10
- call write_string
-
- mov ah,unk_color
- mov dx,1410h
- mov si,offset text12x
- call write_string
-
- mov ah,title_color ;Display "Press Esc to
- mov dx,181Eh ;exit"
- mov si,offset text23
- call write_string
- ret
- draw_screen endp
-
- ;****************************************************************************
- ; DRAW_MAP draws the memory map stored in the MAP array.
- ;****************************************************************************
-
- draw_map proc near
- mov dx,0C0Ah ;Initialize DX
- mov si,offset map ;Point SI to MAP array
-
- mov cx,6 ;Do six rows, saving CX and
- dmap1: push cx ;and DX prior to each pass
- push dx ;through the loop
-
- mov cx,4 ;Do four sets of columns in
- dmap2: push cx ;each row, each time saving
- push dx ;CX and DX at the beginning
-
- mov cx,8 ;Eight characters per set
- dmap3: push cx ;Save CX and DX
- push dx
- lodsb ;Get the MAP character
-
- mov ah,fore_color ;Load the appropriate video
- cmp al,"R" ;attribute in AH
- jne dmap4
- mov ah,rom_color
- jmp short dmap8
-
- dmap4: cmp al,"+"
- jne dmap5
- mov ah,ram_color
- jmp short dmap8
-
- dmap5: cmp al,"V"
- jne dmap6
- mov ah,video_color
- jmp short dmap8
-
- dmap6: cmp al,"E"
- jne dmap7
- mov ah,ems_color
- jmp short dmap8
-
- dmap7: cmp al,"U"
- jne dmap8
- mov ah,unk_color
-
- dmap8: call write_char ;Output the character
- pop dx ;Retrieve row and column
- inc dl ;Increment the column number
- pop cx ;Retrieve count in CX
- loop dmap3 ;Loop until done
-
- pop dx ;Retrieve row and column
- add dl,9 ;Add 9 to the column number
- pop cx ;Retrieve set count in CX
- loop dmap2 ;Loop until done
-
- pop dx ;Retrieve row and column
- dec dh ;Decrement the row number
- mov dl,0Ah ;Reinitialize column number
- pop cx ;Retrieve row count in CX
- loop dmap1 ;Loop until done
- ret
- draw_map endp
-
- ;****************************************************************************
- ; TEST_CRTC tests for the presence of a 6845-style CRT controller at the
- ; port address specified in DX. On return, carry is clear if a CRTC was
- ; detected, or set if no CRTC was found.
- ;****************************************************************************
-
- test_crtc proc near
- mov al,0Fh ;Set CRTC address register to
- out dx,al ;0Fh (Cursor Address Low)
- jmp short $+2 ;I/O delay
- jmp short $+2
-
- inc dx ;Point DX to data register
- in al,dx ;Read Cursor Address Low
- mov ah,al ;Save result in AH
- not al ;Flip the bits in AL
- mov bl,al ;Save this result in BL
- out dx,al ;Write the new value back
- jmp short $+2 ;I/O delay
- jmp short $+2
-
- in al,dx ;Read Cursor Address Low
- jmp short $+2 ;I/O delay
- jmp short $+2
- xchg al,ah ;Swap AH and AL
- out dx,al ;Restore original value
- cmp ah,bl ;No CRTC here is AH is not
- jne test1 ;equal to BL
-
- clc ;Clear the carry flag
- ret ;and return
-
- test1: stc ;Set the carry flag
- ret ;and return
- test_crtc endp
-
- ;****************************************************************************
- ; CLEAR_SCREEN clears the screen. Set MAXROW equal to the number of rows
- ; displayed minus 1 before calling this procedure.
- ;****************************************************************************
-
- clear_screen proc near
- mov ax,0600h
- mov bh,07h
- mov cx,0000h
- mov dh,maxrow
- mov dl,4Fh
- int 10h
- ret
- clear_screen endp
-
- ;****************************************************************************
- ; DRAWBOX draws a box in text mode using single-line graphics characters.
- ; On entry, CX holds the row and column address of the upper left corner,
- ; and DX holds the row and column address of the lower right corner. AH
- ; holds the video attribute used to draw the box.
- ;****************************************************************************
-
- rows dw 0 ;Number of rows
- columns dw 0 ;Number of columns
-
- drawbox proc near
- sub dh,ch ;Compute the number of rows
- dec dh ;inside the box
- mov byte ptr rows,dh
- sub dl,cl ;Then compute the number of
- dec dl ;columns
- mov byte ptr columns,dl
-
- push ax ;Save video attribute
- mov dx,cx ;Place starting address in DX
- call compute_address ;Compute the memory address
- mov di,ax ;Transfer result to DI
- mov es,video_segment ;Point ES to the video buffer
- pop ax ;Retrieve video attribute
- push di ;Save video buffer address
-
- mov al,0DAh ;Draw the upper left corner
- stosw ;of the box
- mov al,0C4h ;Draw the upper horizontal
- mov cx,columns
- rep stosw
- mov al,0BFh ;Draw the upper right corner
- stosw ;of the box
-
- sub di,2 ;Point DI to the end of the
- add di,line_length ;second row of the box
- mov cx,rows ;Draw right vertical
- call draw_vertical
- mov al,0D9h ;Draw the lower right corner
- stosw ;of the box
-
- pop di ;Retrieve address
- add di,line_length ;Point DI to the second row
- mov cx,rows ;Draw left vertical
- call draw_vertical
- mov al,0C0h ;Draw the lower left corner
- stosw ;of the box
-
- mov al,0C4h ;Draw the lower horizontal
- mov cx,columns
- rep stosw
- ret
- drawbox endp
-
- ;****************************************************************************
- ; DRAW_VERTICAL draws a vertical line. On entry, ES:DI points to the
- ; location in the video buffer, AH holds the video attribute, and CX
- ; holds the length of the line in rows.
- ;****************************************************************************
-
- draw_vertical proc near
- mov al,0B3h ;Load AL with ASCII code
- dv_loop: stosw ;Write one character
- sub di,2 ;Point DI to the character
- add di,line_length ;cell on the next row
- loop dv_loop ;Loop until done
- ret
- draw_vertical endp
-
- ;****************************************************************************
- ; WRITE_STRING writes an ASCIIZ string at the row and column address
- ; specified in DH and DL. On entry, AH contains the video attribute and
- ; DS:SI points to the string.
- ;****************************************************************************
-
- write_string proc near
- push ax ;Save video attribute
- call compute_address ;Compute the memory address
- mov di,ax ;Transfer result to DI
- mov es,video_segment ;Point ES to the video buffer
- pop ax ;Retrieve video attribute
-
- ws_loop: lodsb ;Get a character
- or al,al ;Exit if it's zero
- jz ws_exit
- stosw ;Display it
- jmp ws_loop ;Loop back for more
- ws_exit: ret
- write_string endp
-
- ;****************************************************************************
- ; WRITE_CHAR writes a character and attribute at the row and column
- ; address specified in DH and DL. On entry, AH holds the video attribute
- ; and AL holds the character's ASCII code.
- ;****************************************************************************
-
- write_char proc near
- push ax ;Save video attribute
- call compute_address ;Compute the memory address
- mov di,ax ;Transfer result to DI
- mov es,video_segment ;Point ES to the video buffer
- pop ax ;Retrieve video attribute
- stosw ;Write the character and
- ret ;attribute and exit
- write_char endp
-
- ;****************************************************************************
- ; COMPUTE_ADDRESS returns in AX the video buffer address that corresponds
- ; to the row and column number passed in DH and DL. Before this procedure
- ; is called, LINE_LENGTH must contain the number of bytes per video line
- ; and VIDEO_OFFSET must contain the offset within the video buffer of the
- ; current video page.
- ;****************************************************************************
-
- compute_address proc near
- mov cl,dl ;Save DL in CL
- mov al,dh ;Get starting row in AL
- cbw ;Convert byte to word in AX
- mul line_length ;Multiply by bytes per row
- mov dl,cl ;Load DL with column number
- shl dx,1 ;Multiply starting column by 2
- add ax,dx ;Add it to AX
- add ax,video_offset ;Add video buffer offset
- ret
- compute_address endp
-
- lastbyte label byte
-
- code ends
- end begin
-