Category : Assembly Language Source Code
Archive   : LOOKMEM2.ZIP
Filename : LOOKMEM.ASM

 
Output of file : LOOKMEM.ASM contained in archive : LOOKMEM2.ZIP
PAGE ,132
TITLE LOOKMEM - LOOK AT MEMORY
SUBTTL LOOK AT MEMORY IN ANY SEGMENT

; SET TABS TO 8
; ;
;***************************************************************************;
; ;
; LOOKMEM Version 8/29/88 ;
; ;
; Copyright (C) John Pulliam 1988 ;
; ;
; For Columbia Data Product Computers and Compatibles ;
; Released to Public Domain ;
; ;
;***************************************************************************;
; ;
; LOOKMEM is a program that lets you take a peek at the contents of the ;
; RAM or ROM memory in your IBM compatible computer. Only the first 1 Meg ;
; of memory may be viewed this way. ;
; ;
; Usage of this program is to just enter the name, "LOOKMEM" and follow ;
; the prompts on the screen. ;
; ;
; This is a new version of LOOKMEM, which was originally released in 1984. ;
; The primary change is in the method of writing to the display. The old ;
; version used the DOS functions and was therefore quite slow. This new ;
; version uses direct screen writes, taking care not to cause any of the ;
; snow on the screen as is common with many machines. As a result of the ;
; different method of writing to the display, computer systems that are ;
; not very compatible will likely not run this program properly. ;
; ;
; An addition is the Find Function for searching memory for a sequence or ;
; string of hex bytes and the Repeat Find fun to find the next occurrence ;
; of the same string. ;
; ;
; Another small change is that the right and left arrow keys now increment ;
; the segment by 10 hex instead of by one as before. ;
; ;
; The author of this program takes no responsibility for any damages ;
; allegedly caused by the use or operation of this program, whether it be ;
; to software, hardware, furniture, household appliances, pets or personal ;
; belongings. ;
; ;
; MS-DOS, PC-DOS, IBM, etc. are copyrighted. ;
; ;
;***************************************************************************;
; ;

CSEG SEGMENT PARA PUBLIC
ASSUME CS:CSEG,DS:CSEG,ES:CSEG

ORG 100H

; Define the constants

CR EQU 13 ; Carriage return code
LF EQU 10 ; Line feed code
BS EQU 08 ; Backspace code
QT EQU 34 ; Quote symbol
BYT EQU 16 ; Number of bytes per line
LINES EQU 8 ; Number of lines to display

; Set up the segment registers

LOOKMEM:MOV AX,CS ; Get current segment
MOV DS,AX ; Set DS to this seg
MOV ES,AX ; Set ES to this seg
MOV SEGADD,AX ; Initialize display segment
CALL INIT ; Get screen & cursor parameters

SIGNON: MOV AH,6 ; Line number
MOV AL,1 ; Column number
MOV SI,OFFSET HELLO ; Text
CALL WRITE ; Display text on screen

; Ask for the segment to display memory from

GETSEG: MOV SI,OFFSET SEGMSG ; Address of message
MOV AX,0801H ; Line 8 / column 1
PUSH AX
CALL WRITE ; Display string function
POP DX
ADD DL,LEN_SEGMSG
DEC DH
CALL CURSE ; Position the cursor at right end of prompt

; Read desired segment
; Keep the same segment if user just presses return

MOV BX,OFFSET SEGADD; Where to store hex input
CALL GETCHARS ; Get input from keyboard
JC GETSEG ; Repeat query if illegal input

; Ask for the starting offset to display memory from

GETOFF: MOV SI,OFFSET STMSG ; Address of message
MOV AX,0901H ; Line & column
PUSH AX
CALL WRITE
POP DX
ADD DL,LEN_STMSG
DEC DH
CALL CURSE ; Position the cursor

; Read desired offset
; Keep the same offset if user just presses return

MOV BX,OFFSET OFFADD; Where to store hex input
CALL GETCHARS ; Get input from keyboard
JC GETOFF ; Repeat query if illegal input
CALL HIDECUR ; Move cursor off the screen to hide it

; Display the segment, offset & data

DISLOOP:CALL DSEGOFF ; Show user segment and offset he chose
CALL DISPLA ; Display memory (at last)

; Display the user prompt on the bottom of the screen

PRTPROM:MOV SI,OFFSET USRPROM ; Point to prompt
MOV AX,24*256+1 ; Row & column
PUSH AX
CALL WRITE
POP DX
ADD DL,LEN_PROM
DEC DH
CALL CURSE ; Position the cursor

; Check for any key inputs

GETINP: MOV AH,8 ; Console input: no echo
INT 21H ; Read
OR AL,AL ; Extended code ?
JZ GETINP_10 ; Go handle cursor controls
CMP AL,01BH ; Escape ?
JNE GETINP_0 ; No, try for others
JMP EXIT ; Yes, leave

GETINP_0:
CMP AL,CR ; Return or enter ?
JNE GETINP_1 ; No, check others
MOV AX,24*256+1 ; Row / column
MOV SI,OFFSET BLANKS
CALL WRITE ; Clear user prompt
MOV AX,900H + LEN_STMSG+2 ; Line & column
MOV SI,OFFSET SPACES4
CALL WRITE ; Clear previous selected offset
JMP GETSEG ; Yes, go get new values for seg/off
GETINP_1:
CMP AL,'8' ; Is it unshifted up arrow or '8' key ?
JE GETINP_10A ; Handle as up arrow
GETINP_2:
CMP AL,'2' ; Is it unshifted down arrow or '2' key ?
JE GETINP_11A ; Yes, handle as down arrow
GETINP_3:
CMP AL,'4' ; Unshifted left arrow or '4' key ?
JNE GETINP_4
JMP GETINP_13A ; Map to shift left
GETINP_4:
CMP AL,'6' ; Unshifted right arrow or '6' key ?
JNE GETINP_9
JMP GETINP_14A
GETINP_9:
MOV DL,7 ; Beep. we don't understand
MOV AH,2
INT 21H
JMP GETINP ; Loop for more input

; Process extended key scan codes

GETINP_10:
INT 21H ; Get second scan code
CMP AL,72 ; Cursor up ?
JNE GETINP_11 ; No
GETINP_10A:
MOV AX,OFFADD
ADD AX,80H ; Increment starting offset (wraps at top)
MOV OFFADD,AX ; Put it back
JMP DISLOOP ; Print seg/off and bytes
GETINP_11:
CMP AL,80 ; Down arrow
JNE GETINP_12 ; Nope
GETINP_11A:
MOV AX,OFFADD
SUB AX,80H ; Decrement (will wrap if bottom)
MOV OFFADD,AX ; Put it back
JMP DISLOOP ; Display new offset and bytes
GETINP_12:
CMP AL,59 ; Help ?
JNE GETINP_12A ; No

CALL CLRSCRN ; Clear bottom of the screen
MOV SI,OFFSET HELPMSG; Point to help
MOV AX,0E01H ; Line 14 & column 1
CALL WRITE
CALL HIDECUR ; Move cursor off the screen to hide it

MOV AH,8 ; Wait for any key to be pressed
INT 21H
OR AL,AL
JNZ DL1 ; Skip if not extended key input

MOV AH,6 ; Get second code of extended pair
MOV DL,0FFH
INT 21H

DL1: CALL CLRSCRN ; Clear bottom of the screen
JMP DISLOOP ; Get from keyboard

GETINP_12A:
CMP AL,60 ; Find ?
JNE GETINP_12B ; Nope
CALL CLRSCRN ; Clear bottom of the screen
CALL FINDIT ; Go "find" a string
JMP DISLOOP

GETINP_12B:
CMP AL,61 ; Repeat Find ?
JNE GETINP_13 ; Nope
CALL CLRSCRN ; Clear bottom of the screen
MOV DI,OFFADD ; Current offset
INC DI ; Start at the NEXT location
MOV AX,SEGADD ; Get starting segment to search from
CALL REP_FIND ; Go "find" the same string
JMP DISLOOP

GETINP_13:
CMP AL,75 ; Left arrow ?
JNE GETINP_14 ; No
GETINP_13A:
SUB SEGADD,10H ; Decrement seg by 10 hex (wrap at bottom)
JMP DISLOOP
GETINP_14:
CMP AL,77 ; Right arrow ?
JNE GETINP_20 ; No
GETINP_14A:
ADD SEGADD,10H ; Increment seg by 10 hex (wrap at top)
JMP DISLOOP
GETINP_20:
JMP GETINP_9

EXIT: CALL RESET ; Reset Video Mode and Active Page
INT 20H ; Return to DOS

.XLIST
SUBTTL MISCELLANEOUS CALLABLE ROUTINES
PAGE +
.LIST
; ;
;***************************************************************************;
; ;
; Number Input Subroutine ;
; ;
; Get four digit number from keyboard, convert to hex and store it ;
; in [BX] ;
; ;
; Backspace and carriage return codes are processed by DOS ;
; ;
; Alters: All registers are altered ;
; ;
;***************************************************************************;
; ;

GETCHARS:
MOV AH,4 ; Max number of characters wanted
MOV DI,OFFSET KBUFSZ ; Keyboard buffer
CALL KYBD ; Input reply

CMP AH,4 ; Want 4 chars excluding the CR
JE GC1 ; Skip if no leading zeros

; Skip to return if user just presses return

OR AH,AH ; Just return pressed ?
JZ GC2
CALL INSERT ; Insert leading zeros

; Convert four ASCII codes into two hex bytes (four hex digits)

GC1: MOV AX,WORD PTR KBUF ; First two ASCII codes
CALL ASC_HEX ; Returns one hex byte
JC GC2 ; Repeat query if illegal input
MOV CS:[BX+1],AL ; Store high segment byte
MOV AX,WORD PTR KBUF+2 ; Third and fourth ASCII codes
CALL ASC_HEX ; Returns one hex byte
JC GC2 ; Repeat query if illegal input
MOV CS:[BX],AL ; Store low segment byte

GC2: JNC GC4
MOV DL,7 ; Beep. we don't understand
MOV AH,2
INT 21H
STC
GC4: RET

; ;
;***************************************************************************;
; ;
; Insert Leading Zeros Subroutine ;
; ;
; Insert leading zeros into keyboard input buffer, KBUF ;
; ;
; Alters: All registers are altered ;
; ;
;***************************************************************************;
; ;

INSERT: STD ; Reverse
MOV AL,4 ; Number of digits in the number
SUB AL,AH ; Number of leading zeros to insert
INS1: MOV DI,OFFSET KBUF+3 ; Destination address
MOV SI,OFFSET KBUF+2 ; Source address
MOV CX,3 ; Loop count
INS2: REP MOVSB ; Move three characters right one place
MOV BYTE PTR [DI],'0'; Insert ASCII zero into left place
DEC AL
JNZ INS1 ; Loop for each zero to add
CLD ; Forward
RET ; Return to caller

PAGE
; ;
;***************************************************************************;
; ;
; Write CR LF To CRT ;
; ;
; Alters: All registers are altered ;
; ;
;***************************************************************************;
; ;

CRLF: MOV SI,OFFSET CRLFM ; Address of 'CR,LF'
XOR AX,AX ; Same row & column
CALL WRITE ; Write CR, LF
RET ; Return to continue
CRLFM DB CR,LF,'$'


; ;
;***************************************************************************;
; ;
; HIDECUR - Hide The Cursor Off-Screen ;
; ;
; Alters: All registers except DI, SI & ES are altered ;
; ;
;***************************************************************************;
; ;

HIDECUR:
PUSH DI ; Save registers
PUSH SI
PUSH ES
MOV DL,79
MOV DH,26 ; Move cursor off the screen to hide it
CALL CURSE
POP ES
POP SI
POP DI
RET

PAGE
; ;
;***************************************************************************;
; ;
; Display The Selected Memory ;
; ;
; Entry: Segadd = Segment to display from ;
; Stadd = Offset to display from ;
; Ascseg = ASCII code of segment ;
; Ascadd = ASCII code of offset ;
; ;
; Alters: All registers are altered ;
; ;
;***************************************************************************;
; ;

DISPLA: PUSH OFFADD ; Save starting offset
PUSH ES ; Save ES register
MOV SI,OFFSET SEGO ; "Seg Off" string
MOV AX,1 ; Left end of same line
CALL WRITE ; Output text

; Output the top line - hex display on left of screen

MOV CX,BYT ; Number of bytes per line
MOV AL,BYTE PTR OFFADD ; Get the low address byte
LUP1: PUSH AX ; Save for next output
CALL HEX_ASC ; Convert to ASCII
MOV SI,OFFSET ASCTOP
MOV BYTE PTR [SI],AH; Save low digit for output
XOR AX,AX ; Keep same line & column
CALL WRITE ; Write it to the display
POP AX ; Get previous digit
INC AL ; Increment for next digit
LOOP LUP1 ; Repeat for the rest of the line
XOR AX,AX ; Same line & column
MOV SI,OFFSET SPACE ; Follow with a blank
CALL WRITE

; Output top line - ASCII display on right of screen

MOV CX,BYT ; Number of bytes per line
MOV AL,BYTE PTR OFFADD ; Get the low address byte
LUP2: PUSH AX ; Save for next output
CALL HEX_ASC ; Convert to ASCII
MOV SI,OFFSET ASCTOP2
MOV BYTE PTR [SI],AH; Store low digit for display later
XOR AX,AX ; Same row & column
CALL WRITE ; Write it on the display
POP AX ; Get previous digit
INC AL ; Increment for next digit
LOOP LUP2 ; Repeat for the rest
CALL CRLF ; CR and LF

MOV BX,LINES ; Number of lines to display
MOV ES,SEGADD ; Fetch segment to display

; Loop here for each line to display

LUP3: PUSH BX ; Save line counter

; Output address at start of line

; Print the segment address on the left margin along with the offset

MOV SI,OFFSET SSTO ; Point to the ASCII segment
MOV AX,1 ; Left end of same line
CALL WRITE ; Display the segment
XOR AX,AX ; Print a colon between segment & offset
MOV SI,OFFSET COLON
CALL WRITE ; Colon
MOV AL,BYTE PTR OFFADD+1 ; Get the first address byte
CALL HEX_ASC ; Convert to ASCII
MOV ASCADD,AX ; Save for output to crt
MOV AL,BYTE PTR OFFADD ; Get the second address byte
CALL HEX_ASC ; Convert it to ASCII too
MOV ASCADD+2,AX ; And save it also

XOR AX,AX
MOV SI,OFFSET ASCADD; Display the offset
CALL WRITE
MOV SI,OFFADD ; Get starting offset
ADD OFFADD,BYT ; Inc address by number of bytes in a line
; for the offset on the next line

; Output one line of data (hex display on left and ASCII display on right)

MOV CX,BYT ; Number of bytes to display in a line
MOV DI,OFFSET ASCCHAR ; Address of ASCII buffer (right end of crt)

LUP4: MOV AL,ES:[SI] ; Pick up next memory byte to display
PUSH SI ; Save this memory pointer
PUSH AX ; Save memory byte
CMP AL,7FH ; See if it can be displayed on crt
JGE DASC1 ; Branch if not
CMP AL,20H
JGE DASC2 ; Branch if yes
DASC1: MOV AL,'.' ; Substitute period
DASC2: MOV [DI],AL ; Store for later display
POP AX ; Retrieve memory byte
CALL HEX_ASC ; Convert it to two ASCII codes
MOV CHARS,AX ; Store them for the hex display
XOR AX,AX
MOV SI,OFFSET CHARS ; We stored the data here
CALL WRITE ; Display the hex data
POP SI ; Get last memory pointer
INC SI ; Increment for next memory pointer
INC DI ; Increment ASCII buffer pointer
LOOP LUP4 ; Repeat until done with this line

XOR AX,AX ; Spaces between hex display & ASCII display
MOV SI,OFFSET SPACES
CALL WRITE

; Output ASCII display on right of crt

; Can't write this as a string because there might be a '$' symbol in it

MOV DI,NXT_POS ; Next position on display screen
MOV SI,OFFSET ASCCHAR ; Point to the symbol to display
MOV ES,SEGADD
MOV CX,BYT ; Number of symbols to display
LUP5: PUSH ES ; Save our memory segment to display from
LODSB ; Next symbol to display
MOV ES,SCREEN ; Fetch display segment
CALL WRITE_ONE ; Display the symbol
INC DI ; Skip past the attribute byte
POP ES ; Get the segment to get data from
LOOP LUP5 ; Repeat for all symbols

CALL CRLF ; Output CR and LF
POP BX ; Restore line counter
DEC BX ; Decrement line counter
JZ DISEND
JMP LUP3 ; Repeat for all lines

DISEND: POP ES ; Restore ES register
POP OFFADD ; Restore starting offset
RET ; Return to calling routine

PAGE
; ;
;***************************************************************************;
; ;
; Keyboard Input Subroutine Version 2/19/84 ;
; ;
; This routine reads ASCII codes from the keyboard into a buffer ;
; ;
; Entry: AH = Max number of characters to read excluding any CR code ;
; DI = FWA of the buffer in which to store the characters ;
; ;
; Exit: AL = The last character read excluding any cr code ;
; AH = The number of characters read excluding BS or CR codes ;
; DI = address of the last character read ;
; One less than buffer FWA if only CR is received ;
; ;
; Backspace and carriage return codes are processed by DOS ;
; ;
; The buffer must have the first two bytes available for storage of ;
; the max number of characters to read and number of characters read ;
; including the carriage return code ;
; ;
; Alters: All registers except BX are altered ;
; ;
;***************************************************************************;
; ;

KYBD: PUSH BX ; Save register
PUSH DI ; Save buffer address
INC AH ; Allow for the CR code
MOV [DI],AH ; Store max number of words to read
MOV AX,0C0AH ; Clear and read keyboard buffer
MOV DX,DI ; Buffer address in DX
INT 21H ; Call DOS
POP DI ; Get buffer address
INC DI
MOV AH,[DI] ; Get number of characters read
MOV BL,AH ; Put in base register
XOR BH,BH
ADD DI,BX ; Set DI to last character position
MOV AL,[DI] ; Get last character read
POP BX ; Restore register
RET ; Return to calling routine

PAGE
; ;
;***************************************************************************;
; ;
; Convert ASCII To Hex Version 3/24/84 ;
; ;
; Modified to allow lower case 'a' thru 'f' ;
; ;
; Convert two ASCII codes in AX to one hex number in AL ;
; ;
; Entry: AL = upper ASCII code ;
; AH = lower ASCII code ;
; Inputs must be '0' - '9', 'A' - 'F' or 'a' - 'f' ;
; ;
; Exit: AL = one hex number (two hex digits, 0 - 9, A - F) ;
; Carry flag is set if an illegal hex digit is in the input ;
; ;
; Alters: Registers AL and AH are altered ;
; ;
; Note: Valid for all hex numbers 00 to FF ;
; ;
;***************************************************************************;
; ;

ASC_HEX:PUSH BX ; Save registers
MOV BX,AX ; Save the ASCII codes
CALL CNVRT1 ; Returns upper digit in lower AL
SHL AL,1 ; Put it in upper AL
SHL AL,1
SHL AL,1
SHL AL,1
XCHG AL,BH ; Save in BH & get lower digit
CALL CNVRT1 ; Returns lower digit in lower AL
OR AL,BH ; Combine both hex digits into AL
POP BX ; Restore registers
CLC ; Clear carry/error flag
RET ; Return to calling routine

CNVRT1: SUB AL,30H ; Partial conversion
JL CERR ; Al < 0 => illegal hex code

; Allow lower case alpha input if legal hex

CMP AL,9 ; Check for 0 - 9
JLE CEND ; Al <= 9 => 0 - 9
AND AL,0DFH ; Force capital letters of A thru F
CMP AL,11H ; Check for A - F
JL CERR ; Al < 11h => Illegal (between '9' and 'A')
SUB AL,7 ; Convert A - F
CMP AL,0FH ; Al > 0fh => Illegal
JG CERR ; Error exit
CEND: RET ; Return to continue

CERR: POP AX ; Erase first return address
SUB AX,AX ; Set result to zero
POP BX ; Adjust stack
STC ; Set carry/error flag
RET ; Return to calling routine

PAGE
; ;
;****************************************************************************;
; ;
; Convert Hex To ASCII Version 8/07/84 ;
; ;
; Convert from two hex digits in AL to two ASCII codes in AX ;
; ;
; Entry: AL = Hex number 00H to FFH ;
; ;
; Exit: AL = Upper ASCII code ;
; AH = Lower ASCII code ;
; ;
; Alters: registers AL and AH are altered ;
; ;
; Note: This conversion is valid for all hex codes ;
; ;
;****************************************************************************;
; ;

HEX_ASC:
MOV AH,AL ; Save upper hex digit
CALL CVRT2 ; Convert hex lower digit
XCHG AH,AL ; Save it in AH / get upper digit to convert
SHR AL,1 ; Shift into low nibble
SHR AL,1
SHR AL,1
SHR AL,1 ; Convert upper hex digit

; Convert one hex digit in lower nibble of AL into one ASCII code in AL

CVRT2: AND AL,0FH ; Separate out one hex digit
ADD AL,90H ; And convert
DAA ; To one
ADC AL,40H ; ASCII code
DAA ; In AL
CVRT4: RET ; Return to calling routine

PAGE
; ;
;***************************************************************************;
; ;
; Display Current Segment And Offset ;
; ;
; Entry: None ;
; ;
; Exit: None ;
; ;
; Alters: registers AX, DX and SI are altered ;
; ;
;***************************************************************************;
; ;

DSEGOFF:
MOV AL,BYTE PTR SEGADD+1 ; Get the first segment byte
CALL HEX_ASC ; Convert to ASCII
MOV SSTO,AX ; Save for output to crt
MOV AL,BYTE PTR SEGADD ; Get the second segment byte
CALL HEX_ASC ; Convert it to ASCII too
MOV SSTO[2],AX ; And save it also

MOV AL,BYTE PTR OFFADD+1 ; Get the first offset byte
CALL HEX_ASC ; Convert to ASCII
MOV OFFSTO,AX ; Save for output to crt
MOV AL,BYTE PTR OFFADD ; Get the second segment byte
CALL HEX_ASC ; Convert it to ASCII too
MOV OFFSTO[2],AX ; And save it also

MOV SI,OFFSET CURSEG; Display segment
MOV AH,11 ; Line no.
MOV AL,1 ; Left end of line
CALL WRITE
MOV SI,OFFSET CUROFF; Display offset
XOR AX,AX ; Keep current line and column
CALL WRITE
CALL DISPLIN
RET

; ;
;***************************************************************************;
; ;
; Display A Line Of Underscores ;
; ;
; Entry: None ;
; ;
; Exit: None ;
; ;
; Alters: None ;
; ;
;***************************************************************************;
; ;

UL DB CR,LF,79 DUP('_'),'$'

DISPLIN:
PUSH CX ; Save registers
PUSH BX
PUSH AX
MOV AX,1 ; Left end of current row
MOV SI,OFFSET UL
CALL WRITE
POP AX ; Restore registers
POP BX
POP CX
RET

PAGE
; ;
;****************************************************************************;
; ;
; FIND a HEX string in memory ;
; ;
; FIND a string in memory starting from the current segment & offset+1 ;
; ;
; Entry: SEGADD = Starting segment where search starts ;
; OFFADD = Starting offset - 1 where search starts ;
; ;
; Exit: SEGADD = Segment where the string was found ;
; OFFADD = Starting offset of the string if found ;
; ;
; Alters: All registers are altered ;
; SEGADD & OFFADD are altered if the string is found ;
; The hex and ASCII displays will be shown on the CRT if found ;
; ;
;****************************************************************************;
; ;

FINDIT: MOV AH,15 ; Line number
MOV AL,1 ; Column number
MOV SI,OFFSET FINDMSG
CALL WRITE ; Display the prompt
MOV DH,17 ; Position cursor in the prompt
MOV DL,23
MOV DI,OFFSET KBUF ; Where to store the ASCII bytes
MOV WORD PTR SRCHCNT,0 ; Clear the count of symbols entered

; Loop here for each byte

FIN2: PUSH DX ; Save cursor position
CALL CURSE ; Position the cursor at right end of prompt

; Loop here for each symbol or digit

MOV BL,0 ; Start with toggle = 0

FIN4: MOV AX,0C01H ; Wait for any key to be pressed
INT 21H ; Read the ASCII code

; Check for valid input

CMP AL,CR ; Go do the search if CR key
JE FIN5

CMP AL,BS ; Check for backspace
JE FIN8
CMP AL,0
JNZ FIN6 ; Quit if extended code
FIN5: JMP FIN15

FIN6: CMP AL,'0' ; Verify legal hex digit
JL FIN7
CMP AL,'9'
JLE FIN13
AND AL,0DFH ; Force capital letters
CMP AL,'F'
JG FIN7
CMP AL,'A'
JGE FIN13 ; Skip if valid hex digit

; Illegal symbol input

FIN7: MOV DL,7 ; Beep, illegal input
MOV AH,2
INT 21H
POP DX ; Cursor position
PUSH DX
CALL CURSE ; Move cursor back to where it was

MOV DL,'_' ; Redisplay underline
MOV AH,2
INT 21H
JMP SHORT FIN10 ; Skip to continue

; Backspace

FIN8: DEC DI ; Decrement buffer location after backspace
CMP DI,OFFSET KBUF
JGE FIN11 ; Branch if not left end of buffer
MOV DI,OFFSET KBUF
MOV DL,7 ; Beep, illegal input at left end of buffer
MOV AH,2
INT 21H
DEC WORD PTR SRCHCNT

; Backspace or Illegal symbol

FIN10: POP DX ; Get cursor position
PUSH DX
CALL CURSE ; Restore cursor
JMP FIN4 ; Loop for next input

; Backspace and not at left end of buffer

FIN11: CMP BL,0 ; Check whether first or second digit of byte
JNZ FIN12 ; Skip if toggle is not 0
POP DX ; Cursor position
DEC DL ; Dec cursor position
PUSH DX ; Save position
DEC DL ; Dec cursor position
CALL CURSE ; Move cursor left one

FIN12: MOV DL,'_' ; Redisplay underline
MOV AH,2
INT 21H
POP DX
DEC DL ; Dec cursor position
PUSH DX
CALL CURSE ; Move cursor left one
XOR BL,1 ; Change toggle after backing up
JMP FIN4 ; Loop for next input

FIN13: XOR BL,1 ; Change toggle after symbol input
STOSB ; Store the ASCII code in the keyboard buffer
INC WORD PTR SRCHCNT
POP DX ; Cursor position
INC DL ; Bump cursor position
PUSH DX ; Save new position
CMP BL,0
JZ FIN14
JMP FIN4 ; Repeat for second digit

FIN14: POP DX ; Get cursor position
INC DL ; Move cursor position to next byte

CMP DI,OFFSET KBUF+8
JGE FIN16 ; Branch to do the search
JMP FIN2 ; Loop for another symbol

FIN15: POP DX ; Adjust stack
CMP AL,0
JNE FIN16
JMP FIN30 ; Quit if extended code

; Convert the inputs to hex for the search

FIN16: CALL CLRSCRN ; Clear bottom of the screen
CALL HIDECUR ; Hide the cursor

MOV CX,SRCHCNT ; Number of digits or symbols entered
SHR CX,1 ; Number of hex bytes
JCXZ FIN30 ; Quit if invalid - only 1 digit
MOV SI,OFFSET KBUF ; Point to the ASCII string of bytes
MOV DI,OFFSET SRCHCHR ; Destination
FIN17: LODSW
CALL ASC_HEX ; Convert to one hex byte
STOSB
LOOP FIN17 ; Loop for all bytes

; Now search from current SEG:OFF for the string of bytes just entered

FIN18: PUSH ES ; Save ES segment
MOV DI,OFFADD ; Current offset
INC DI ; Start at the NEXT location
MOV AX,SEGADD ; Get starting segment to search
DEC AX
MOV ES,AX ; Put first seg - 1 in ES
CMP AX,0FFFFH
JNE FIN20 ; Skip if not starting with segment zero
INC AX
JMP SHORT FIN22 ; Skip check for zero if starting at zero

; Start searching a new segment for the string. Quit after Segment FFFFH

FIN20: MOV AX,ES ; Get the previous segment
INC AX ; Step to next segment to scan
OR AX,AX
JNZ FIN22 ; Skip over "Not Found message

MOV AH,18 ; Line number
MOV AL,36 ; Column number
MOV SI,OFFSET NOTFND
CALL WRITE ; Display the prompt
MOV DL,7 ; Beep
MOV AH,2
INT 21H

MOV AL,12 ; Delay so message can be seen
XOR CX,CX
LOOP $
DEC AL
JNZ $-4
JMP SHORT FIN29 ; Quit at end of memory

; Repeat Find Entry Point

REP_FIND:
PUSH ES
CALL HIDECUR ; Hide the cursor

FIN22: MOV ES,AX ; Put the segment in ES

; Search for the first character in the string for a starting point

MOV CX,16
MOV AL,SRCHCHR ; First hex byte in the string
REPNE SCASB
JE FIN24 ; Found the first symbol so go check for more
SUB DI,DI ; Offset is 0 for the rest of the segments
JMP SHORT FIN20 ; Loop to get the next segment

; Search for the string

FIN24: DEC DI ; Point to the first symbol we just found
MOV SI,OFFSET SRCHCHR ; Point to first symbol of string to find
MOV CX,SRCHCNT ; Length of string to find
SHR CX,1
REPE CMPSB ;
JE FIN28 ; Found it so skip to display it
SUB DI,DI ; Offset is 0 for the rest of the segments
JMP SHORT FIN20 ; Loop to get the next segment

FIN28: MOV AX,SRCHCNT
SHR AX,1
SUB DI,AX ; Point to the start of the string we found
MOV SEGADD,ES ; Save the segment where it was found
MOV OFFADD,DI

FIN29: POP ES ; Restore ES segment
FIN30: RET ; Return to calling routine

.XLIST
SUBTTL Video & Display Subroutines
.LIST

CGA EQU 0B800H ; Screen segment - color/graphics
MONO EQU 0B000H ; Screen segment - b & w adapter

CGAFLG DB 0 ; 1 = CGA, 0 = MONO (default)
SCREEN DW 0 ; Base segment of display screen
RET_ADD DW 0 ; Address of Horizontal Retrace Status Register

VMODE DB 0 ; Original video mode
VCOL DB 0 ; Original number of video columns
VPAGE DB 0 ; Original active video page
CURSIZE DW 0 ; Original cursor size or lines


; ;
;***************************************************************************;
; ;
; Init - Initialize Screen Routines ;
; ;
; Entry: None ;
; ;
; Exit: None ;
; ;
; Alters: All registers except ES are altered ;
; ;
;***************************************************************************;
; ;

; Init - Get Horizontal Retrace Status Register Address ;

FLAG_SEG EQU 40H ; Segment containing DOS flags
VID_BASE EQU 63H ; Location of base address of video controller

INIT: PUSH ES ; Save ES
MOV AX,FLAG_SEG ; Segment containing DOS flags
MOV ES,AX
MOV AX,ES:VID_BASE ; Get base address of video controller
ADD AX,6 ; Horizontal Retrace Status Register Address
MOV RET_ADD,AX ; Save it

; Get base address of the display screen

MOV WORD PTR SCREEN,MONO; Screen base for mono
INT 11H ; Get hardware flags.
TEST AX,10H ; See if we have a cga or monochrome
JNZ INIT2 ; Skip if mono display
MOV WORD PTR SCREEN,CGA; Screen base for cga
MOV BYTE PTR CGAFLG,1 ; Set flag for cga

; Get current video mode

INIT2: MOV AH,15
INT 10H ; Get current video mode & save it
MOV VMODE,AL ; Current video mode
MOV VCOL,AH ; Number of columns
MOV VPAGE,BH ; Current active video page

MOV AH,3
INT 10H ; Get cursor type or size
MOV CURSIZE,CX ; Save it to be restored at end

; Select video mode 3, 80x25 color, alpha if CGA or mode 7 if MONO adapter

MOV AX,3 ; Select video mode 3
CMP BYTE PTR CGAFLG,0 ; 1 = CGA, 0 = MONO
JNZ INIT4 ; Branch if CGA
MOV AL,7 ; Select video mode 7
INIT4: INT 10H

; Select active page 0

MOV AX,500H ; Select active page 0
INT 10H
POP ES

; Delay to try to prevent the "screen jump" before writing to it

MOV AL,3
XOR CX,CX
INIT5: LOOP INIT5
DEC AL
JNZ INIT5

RET

; ;
;***************************************************************************;
; ;
; CURSE - Position Cursor Routine ;
; ;
; Place the block cursor at DH, DL (Row, Column - 0,0 is upper left) ;
; ;
; Entry: None ;
; ;
; Exit: None ;
; ;
; Alters: All registers are altered except AX & DX ;
; ;
;***************************************************************************;
; ;

CURSE: PUSH AX ; Save registers
PUSH BX

MOV AH,2 ; Set cursor position
MOV BH,VPAGE ; Our video page
INT 10H

MOV AH,1 ; Set cursor size
MOV CX,7 ; Starting line 0, ending line 7
INT 10H

POP BX ; Restore registers
POP AX
RET

; ;
;***************************************************************************;
; ;
; Reset The Original Video Mode And Cursor Size ;
; ;
; ;
; Entry: None ;
; ;
; Exit: None ;
; ;
; Alters: All registers are altered ;
; ;
;***************************************************************************;
; ;

RESET: MOV AH,0
MOV AL,VMODE ; Restore original video mode
INT 10H

MOV AH,5
MOV AL,VPAGE ; Restore original video page
INT 10H

MOV AH,1 ; Restore original cursor size
MOV CX,CURSIZE ; Get original cursor size
INT 10H

RET

PAGE
; ;
;***************************************************************************;
; ;
; WRITE an ASCII String On The Display ;
; ;
; Entry: ;
; AH = Line number (1 - 24) (if 0, start at current position) ;
; AL = Char position (1 - 80) (if 0, start at current position) ;
; SI = Offset address of the string ;
; The string must be terminated with a '$' ;
; ;
; Exit: ;
; AH points to the start of the next line ;
; AL points to the next char position in the line ;
; NXT_POS contains the next screen offset ;
; ;
; Alters: All registers except AX & SI are preserved ;
; ;
;***************************************************************************;
; ;

LINE EQU 160 ; Number of bytes per display line
MLINE EQU 14 ; Highest line to use for text messages

LINENO DB 0 ; Current line number-1
CHARPOS DW 0 ; Current character position-1

WRITE: PUSH DI ; Save registers
PUSH CX
PUSH ES
MOV ES,SCREEN ; Get screen segment

OR AH,AH ; 0 = Use pre-selected display line
JZ W1 ; Keep same line number
DEC AH ; Make line index of 0 - 23
JL W8 ; Quit if too small
CMP AH,23
JG W8 ; Quit if too big
MOV LINENO,AH ; Save line # -1

W1: DEC AL
JL W2 ; Neg = use pre-selected column number
MOV BYTE PTR CHARPOS,AL; Save position -1
W2: MOV AH,LINENO ; Get line number-1
MOV AL,LINE ; Number of bytes in a line
MUL AH ; Offset = (line-1) * (bytes per line)
MOV DI,AX ; Starting offset of the line in DI
ADD DI,CHARPOS ; Add for starting position within the line
ADD DI,CHARPOS ; Add to account for the attribute
MOV CX,80 ; Max length of a line
SUB CX,CHARPOS ; Number characters to end of line

W3: LODSB ; Get next character of message
CMP AL,'$' ; Finished if '$'
JE W8 ; Skip when finished

CMP AL,CR
JNE W4
MOV WORD PTR CHARPOS,0
JMP SHORT W2 ; Restart this line after CR

W4: CMP AL,LF
JNE W5 ; Skip if not LF

ADD DI,LINE ; Move down one line after LF
INC BYTE PTR LINENO
JMP SHORT W3 ; Loop back without decrementing counter

W5: CALL WRITE_ONE ; Write this character on screen
INC DI ; Skip past attribute byte
MOV NXT_POS,DI ; Save next screen offset position
INC WORD PTR CHARPOS; Bump the column
CMP WORD PTR CHARPOS,80
JLE W6
MOV WORD PTR CHARPOS,0

W6: LOOP W3 ; Repeat for the rest of the line

INC BYTE PTR LINENO
JMP SHORT W1 ; Repeat for the rest of the lines

W8: POP ES ; Restore the registers
POP CX
POP DI
RET ; Return to calling routine

; ;
;***************************************************************************;
; ;
; WRITE_ONE Character To The Display ;
; ;
; Entry: Al = Character to write on the display screen ;
; DI = Offset into the display screen ;
; ES = Screen segment ;
; ;
; Exit: DI is incremented by one before exit ;
; ;
; Alters: Register DX is altered ;
; ;
; There is only time to write one (1) symbol during the horizontal ;
; retrace without creating any snow. ;
; ;
;***************************************************************************;
; ;

WRITE_ONE:
PUSH AX ; Save registers
PUSH BX
MOV BL,AL ; Save the character to write
MOV DX,RET_ADD ; Address of status register

W_ONE1: IN AL,DX ; Read horizontal retrace status
SHR AL,1 ; Shift bit zero into carry bit
JC W_ONE1 ; Wait for end of horizontal retrace

CLI ; Disable interrupts during write to screen
W_ONE2: IN AL,DX ; Read horizontal retrace status
SHR AL,1
JNC W_ONE2 ; Wait for start of horizontal retrace

MOV ES:[DI],BL ; Write the character on the display

STI ; Enable interrupts after screen write
INC DI ; Move pointer
POP BX ; Restore registers
POP AX
RET

; ;
;***************************************************************************;
; ;
; CLRSCRN - Clear The Screen From "MLINE" Through Line 24 ;
; ;
; Entry: None ;
; ;
; Exit: None ;
; ;
; Alters: Register DX is altered ;
; ;
;***************************************************************************;
; ;

CLRSCRN:
PUSH AX ; Save registers
PUSH CX
PUSH DI
PUSH ES

MOV CX,(26-MLINE)*LINE/2 ; Number of characters to erase
MOV DI,(MLINE-1)*LINE ; Initial offset into display screen

CMP BYTE PTR CGAFLG,0
JZ CLR1 ; Skip if mono

; Turn off the video

MOV DX,RET_ADD ; Status register address (03DA hex)
SUB DX,2 ; Mode control register (03D8 hex)
MOV AL,1 ; 80X25 alpha color, video off
OUT DX,AL

CLR1: MOV AL,' ' ; Blank symbol
MOV ES,SCREEN ; Set ES to screen segment
CLR2: STOSB ; Write one blank on the display
INC DI ; Skip past attribute byte
LOOP CLR2 ; Loop for entire display

CMP BYTE PTR CGAFLG,0
JZ CLR3 ; Skip if MONO

; Turn on the video

MOV DX,RET_ADD ; Status register address (03DA hex)
SUB DX,2 ; Mode control register (03D8 hex)
MOV AL,9 ; 80X25 alpha color, video on
OUT DX,AL

CLR3: POP ES ; Restore registers
POP DI
POP CX
POP AX
RET ; Return to calling routine

.XLIST
SUBTTL Messages and Data Storage
PAGE +
.LIST

; Messages And Data Storage

HELLO DB 'LOOKMEM Interactive Memory Display Version 8/29/88$'

SEGO DB CR,LF,LF,'Seg Off $'

HELPMSG DB 'LOOKMEM Help : ',CR,LF
DB 24,' Displays the next 128 bytes',CR,LF
DB 25,' Displays the previous 128 bytes',CR,LF
DB 16,' Increments the current segment by 10H',CR,LF
DB 17,' Decrements the current segment by 10H',CR,LF
DB 17,196,217,' Specify new segments or offsets',CR,LF
DB 'Esc Exits from LOOKMEM to DOS',CR,LF
DB 'F1 Displays this help text',CR,LF
DB 'F2 Find a string from current seg:off',CR,LF
DB 'F3 Find Next occurrence of same string',CR,LF,LF
DB ' Copyright (C) John Pulliam 1988',CR,LF
DB ' (press any key to continue)$'
LEN_HELP EQU $ - 2 - OFFSET HELP

FINDMSG DB 'FIND a hex string of up to 4 bytes starting from '
DB 'the currently',CR,LF,'displayed segment & offset',CR,LF,LF
DB 'Enter the hex string : __ __ __ __$'

NOTFND DB 'Not Found$'

CURSEG DB 'Current Segment : '
SSTO DW 0,0
DB '$'

CUROFF DB ' Current Offset : '
OFFSTO DW 0,0
DB '$'
SPACE DB ' $'
SPACES DB ' $'
SPACES4 DB ' $'
COLON DB ':$'

USRPROM DB 'Press Esc, ',16,', ',17,', ',24,', ',25,','
DB ' F1 (help), F2 (find), F3 (find next), or ',17,196,217,' :$'
LEN_PROM EQU $ - 1 - OFFSET USRPROM
BLANKS DB LEN_PROM + 1 DUP(' '),'$'

SEGMSG DB 'Enter the segment address in hex (',17,196,217,' for no '
DB 'change) : $'
LEN_SEGMSG EQU $ - 6 - OFFSET SEGMSG

STMSG DB 'Enter the offset address in hex (',17,196,217
DB ' for no change) : $'
LEN_STMSG EQU $ - 6 - OFFSET STMSG

ASCTOP DB ' $' ; Buffer for top line of hex display
ASCTOP2 DB ' $' ; Buffer for top line of ASCII display

CHARS DW ' ' ; Buffer for hex display
DB ' $'

ASCCHAR DB 16 DUP(' ') ; Buffer for ASCII display

NXT_POS DW 0 ; Next offset position in display

SEGADD DW 0 ; Segment to display (hex)
ASCSEG DW 0,0 ; Segment to display (ASCII)
DB ' $'

OFFADD DW 0 ; Offset to display (hex)
ASCADD DW 0,0 ; Offset to display (ASCII)
DB ' $'
KBUFSZ DB 0,0 ; Keyboard input buffer
KBUF DB ' $' ; Keyboard input data, 8 ASCII symbols
SRCHCNT DW 0
SRCHCHR DB 0,0,0,0

CSEG ENDS
END LOOKMEM


  3 Responses to “Category : Assembly Language Source Code
Archive   : LOOKMEM2.ZIP
Filename : LOOKMEM.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/