home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / asm / LOOKMEM2.ZIP / LOOKMEM.ASM next >
Encoding:
Assembly Source File  |  1988-08-29  |  38.9 KB  |  1,347 lines

  1.     PAGE    ,132
  2.     TITLE    LOOKMEM - LOOK AT MEMORY
  3.     SUBTTL    LOOK AT MEMORY IN ANY SEGMENT
  4.  
  5. ; SET TABS TO 8
  6. ;                                        ;
  7. ;***************************************************************************;
  8. ;                                        ;
  9. ;               LOOKMEM  Version 8/29/88                ;
  10. ;                                        ;
  11. ;               Copyright (C) John Pulliam  1988             ;
  12. ;                                        ;
  13. ;          For Columbia Data Product Computers and Compatibles        ;
  14. ;             Released to Public Domain                ;
  15. ;                                        ;
  16. ;***************************************************************************;
  17. ;                                        ;
  18. ;  LOOKMEM is a program that lets you take a peek at the contents of the    ;
  19. ;  RAM or ROM memory in your IBM compatible computer.  Only the first 1 Meg ;
  20. ;  of memory may be viewed this way.                        ;
  21. ;                                        ;
  22. ;  Usage of this program is to just enter the name, "LOOKMEM" and follow    ;
  23. ;  the prompts on the screen.                            ;
  24. ;                                        ;
  25. ;  This is a new version of LOOKMEM, which was originally released in 1984. ;
  26. ;  The primary change is in the method of writing to the display.  The old  ;
  27. ;  version used the DOS functions and was therefore quite slow.  This new   ;
  28. ;  version uses direct screen writes, taking care not to cause any of the   ;
  29. ;  snow on the screen as is common with many machines.    As a result of the  ;
  30. ;  different method of writing to the display, computer systems that are    ;
  31. ;  not very compatible will likely not run this program properly.        ;
  32. ;                                        ;
  33. ;  An addition is the Find Function for searching memory for a sequence or  ;
  34. ;  string of hex bytes and the Repeat Find fun to find the next occurrence  ;
  35. ;  of the same string.                                ;
  36. ;                                        ;
  37. ;  Another small change is that the right and left arrow keys now increment ;
  38. ;  the segment by 10 hex instead of by one as before.                ;
  39. ;                                        ;
  40. ;  The author of this program takes no responsibility for any damages        ;
  41. ;  allegedly caused by the use or operation of this program, whether it be  ;
  42. ;  to software, hardware, furniture, household appliances, pets or personal ;
  43. ;  belongings.                                    ;
  44. ;                                        ;
  45. ;  MS-DOS, PC-DOS, IBM, etc. are copyrighted.                    ;
  46. ;                                        ;
  47. ;***************************************************************************;
  48. ;                                        ;
  49.  
  50.     CSEG    SEGMENT PARA PUBLIC
  51.     ASSUME    CS:CSEG,DS:CSEG,ES:CSEG
  52.  
  53.     ORG    100H
  54.  
  55. ;  Define the constants
  56.  
  57. CR    EQU    13        ; Carriage return code
  58. LF    EQU    10        ; Line feed code
  59. BS    EQU    08        ; Backspace code
  60. QT    EQU    34        ; Quote symbol
  61. BYT    EQU    16        ; Number of bytes per line
  62. LINES    EQU    8        ; Number of lines to display
  63.  
  64. ;  Set up the segment registers
  65.  
  66. LOOKMEM:MOV    AX,CS        ; Get current segment
  67.     MOV    DS,AX        ; Set DS to this seg
  68.     MOV    ES,AX        ; Set ES to this seg
  69.     MOV    SEGADD,AX    ; Initialize display segment
  70.     CALL    INIT        ; Get screen & cursor parameters
  71.  
  72. SIGNON: MOV    AH,6        ; Line number
  73.     MOV    AL,1        ; Column number
  74.     MOV    SI,OFFSET HELLO ; Text
  75.     CALL    WRITE        ; Display text on screen
  76.  
  77. ;  Ask for the segment to display memory from
  78.  
  79. GETSEG: MOV    SI,OFFSET SEGMSG ; Address of message
  80.     MOV    AX,0801H    ; Line 8 / column 1
  81.     PUSH    AX
  82.     CALL    WRITE        ; Display string function
  83.     POP    DX
  84.     ADD    DL,LEN_SEGMSG
  85.     DEC    DH
  86.     CALL    CURSE        ; Position the cursor at right end of prompt
  87.  
  88. ;  Read desired segment
  89. ;  Keep the same segment if user just presses return
  90.  
  91.     MOV    BX,OFFSET SEGADD; Where to store hex input
  92.     CALL    GETCHARS    ; Get input from keyboard
  93.     JC    GETSEG        ; Repeat query if illegal input
  94.  
  95. ;  Ask for the starting offset to display memory from
  96.  
  97. GETOFF: MOV    SI,OFFSET STMSG ; Address of message
  98.     MOV    AX,0901H    ; Line & column
  99.     PUSH    AX
  100.     CALL    WRITE
  101.     POP    DX
  102.     ADD    DL,LEN_STMSG
  103.     DEC    DH
  104.     CALL    CURSE        ; Position the cursor
  105.  
  106. ;  Read desired offset
  107. ;  Keep the same offset if user just presses return
  108.  
  109.     MOV    BX,OFFSET OFFADD; Where to store hex input
  110.     CALL    GETCHARS    ; Get input from keyboard
  111.     JC    GETOFF        ; Repeat query if illegal input
  112.     CALL    HIDECUR     ; Move cursor off the screen to hide it
  113.  
  114. ;  Display the segment, offset & data
  115.  
  116. DISLOOP:CALL    DSEGOFF     ; Show user segment and offset he chose
  117.     CALL    DISPLA        ; Display memory (at last)
  118.  
  119. ;  Display the user prompt on the bottom of the screen
  120.  
  121. PRTPROM:MOV    SI,OFFSET USRPROM ; Point to prompt
  122.     MOV    AX,24*256+1    ; Row & column
  123.     PUSH    AX
  124.     CALL    WRITE
  125.     POP    DX
  126.     ADD    DL,LEN_PROM
  127.     DEC    DH
  128.     CALL    CURSE        ; Position the cursor
  129.  
  130. ;  Check for any key inputs
  131.  
  132. GETINP: MOV    AH,8        ; Console input: no echo
  133.     INT    21H        ; Read
  134.     OR    AL,AL        ; Extended code ?
  135.     JZ    GETINP_10    ; Go handle cursor controls
  136.     CMP    AL,01BH     ; Escape ?
  137.     JNE    GETINP_0    ; No, try for others
  138.     JMP    EXIT        ; Yes, leave
  139.  
  140. GETINP_0:
  141.     CMP    AL,CR        ; Return or enter ?
  142.     JNE    GETINP_1    ; No, check others
  143.     MOV    AX,24*256+1    ; Row / column
  144.     MOV    SI,OFFSET BLANKS
  145.     CALL    WRITE        ; Clear user prompt
  146.     MOV    AX,900H + LEN_STMSG+2 ; Line & column
  147.     MOV    SI,OFFSET SPACES4
  148.     CALL    WRITE        ; Clear previous selected offset
  149.     JMP    GETSEG        ; Yes, go get new values for seg/off
  150. GETINP_1:
  151.     CMP    AL,'8'        ; Is it unshifted up arrow or '8' key ?
  152.     JE    GETINP_10A    ; Handle as up arrow
  153. GETINP_2:
  154.     CMP    AL,'2'        ; Is it unshifted down arrow or '2' key ?
  155.     JE    GETINP_11A    ; Yes, handle as down arrow
  156. GETINP_3:
  157.     CMP    AL,'4'        ; Unshifted left arrow or '4' key ?
  158.     JNE    GETINP_4
  159.     JMP    GETINP_13A    ; Map to shift left
  160. GETINP_4:
  161.     CMP    AL,'6'        ; Unshifted right arrow or '6' key ?
  162.     JNE    GETINP_9
  163.     JMP    GETINP_14A
  164. GETINP_9:
  165.     MOV    DL,7        ; Beep. we don't understand
  166.     MOV    AH,2
  167.     INT    21H
  168.     JMP    GETINP        ; Loop for more input
  169.  
  170. ;  Process extended key scan codes
  171.  
  172. GETINP_10:
  173.     INT    21H        ; Get second scan code
  174.     CMP    AL,72        ; Cursor up ?
  175.     JNE    GETINP_11    ; No
  176. GETINP_10A:
  177.     MOV    AX,OFFADD
  178.     ADD    AX,80H        ; Increment starting offset (wraps at top)
  179.     MOV    OFFADD,AX    ; Put it back
  180.     JMP    DISLOOP     ; Print seg/off and bytes
  181. GETINP_11:
  182.     CMP    AL,80        ; Down arrow
  183.     JNE    GETINP_12    ; Nope
  184. GETINP_11A:
  185.     MOV    AX,OFFADD
  186.     SUB    AX,80H        ; Decrement (will wrap if bottom)
  187.     MOV    OFFADD,AX    ; Put it back
  188.     JMP    DISLOOP     ; Display new offset and bytes
  189. GETINP_12:
  190.     CMP    AL,59        ; Help ?
  191.     JNE    GETINP_12A    ; No
  192.  
  193.     CALL    CLRSCRN     ; Clear bottom of the screen
  194.     MOV    SI,OFFSET HELPMSG; Point to help
  195.     MOV    AX,0E01H    ; Line 14 & column 1
  196.     CALL    WRITE
  197.     CALL    HIDECUR        ; Move cursor off the screen to hide it
  198.  
  199.     MOV    AH,8        ; Wait for any key to be pressed
  200.     INT    21H
  201.     OR    AL,AL
  202.     JNZ    DL1        ; Skip if not extended key input
  203.  
  204.     MOV    AH,6        ; Get second code of extended pair
  205.     MOV    DL,0FFH
  206.     INT    21H
  207.  
  208. DL1:    CALL    CLRSCRN     ; Clear bottom of the screen
  209.     JMP    DISLOOP     ; Get from keyboard
  210.  
  211. GETINP_12A:
  212.     CMP    AL,60        ; Find ?
  213.     JNE    GETINP_12B    ; Nope
  214.     CALL    CLRSCRN     ; Clear bottom of the screen
  215.     CALL    FINDIT        ; Go "find" a string
  216.     JMP    DISLOOP
  217.  
  218. GETINP_12B:
  219.     CMP    AL,61        ; Repeat Find ?
  220.     JNE    GETINP_13    ; Nope
  221.     CALL    CLRSCRN     ; Clear bottom of the screen
  222.     MOV    DI,OFFADD    ; Current offset
  223.     INC    DI        ; Start at the NEXT location
  224.     MOV    AX,SEGADD    ; Get starting segment to search from
  225.     CALL    REP_FIND    ; Go "find" the same string
  226.     JMP    DISLOOP
  227.  
  228. GETINP_13:
  229.     CMP    AL,75        ; Left arrow ?
  230.     JNE    GETINP_14    ; No
  231. GETINP_13A:
  232.     SUB    SEGADD,10H    ; Decrement seg by 10 hex (wrap at bottom)
  233.     JMP    DISLOOP
  234. GETINP_14:
  235.     CMP    AL,77        ; Right arrow ?
  236.     JNE    GETINP_20    ; No
  237. GETINP_14A:
  238.     ADD    SEGADD,10H    ; Increment seg by 10 hex (wrap at top)
  239.     JMP    DISLOOP
  240. GETINP_20:
  241.     JMP    GETINP_9
  242.  
  243. EXIT:    CALL    RESET        ; Reset Video Mode and Active Page
  244.     INT    20H        ; Return to DOS
  245.  
  246.     .XLIST
  247.     SUBTTL    MISCELLANEOUS CALLABLE ROUTINES
  248.     PAGE    +
  249.     .LIST
  250. ;                                        ;
  251. ;***************************************************************************;
  252. ;                                        ;
  253. ;    Number Input Subroutine                         ;
  254. ;                                        ;
  255. ;    Get four digit number from keyboard, convert to hex and store it    ;
  256. ;    in [BX]                                 ;
  257. ;                                        ;
  258. ;    Backspace and carriage return codes are processed by DOS        ;
  259. ;                                        ;
  260. ;    Alters: All registers are altered                    ;
  261. ;                                        ;
  262. ;***************************************************************************;
  263. ;                                        ;
  264.  
  265. GETCHARS:
  266.     MOV    AH,4        ; Max number of characters wanted
  267.     MOV    DI,OFFSET KBUFSZ ; Keyboard buffer
  268.     CALL    KYBD        ; Input reply
  269.  
  270.     CMP    AH,4        ; Want 4 chars excluding the CR
  271.     JE    GC1        ; Skip if no leading zeros
  272.  
  273. ;  Skip to return if user just presses return
  274.  
  275.     OR    AH,AH        ; Just return pressed ?
  276.     JZ    GC2
  277.     CALL    INSERT        ; Insert leading zeros
  278.  
  279. ;  Convert four ASCII codes into two hex bytes (four hex digits)
  280.  
  281. GC1:    MOV    AX,WORD PTR KBUF ; First two ASCII codes
  282.     CALL    ASC_HEX     ; Returns one hex byte
  283.     JC    GC2        ; Repeat query if illegal input
  284.     MOV    CS:[BX+1],AL    ; Store high segment byte
  285.     MOV    AX,WORD PTR KBUF+2 ; Third and fourth ASCII codes
  286.     CALL    ASC_HEX     ; Returns one hex byte
  287.     JC    GC2        ; Repeat query if illegal input
  288.     MOV    CS:[BX],AL    ; Store low segment byte
  289.  
  290. GC2:    JNC    GC4
  291.     MOV    DL,7        ; Beep. we don't understand
  292.     MOV    AH,2
  293.     INT    21H
  294.     STC
  295. GC4:    RET
  296.  
  297. ;                                        ;
  298. ;***************************************************************************;
  299. ;                                        ;
  300. ;    Insert Leading Zeros Subroutine                     ;
  301. ;                                        ;
  302. ;    Insert leading zeros into keyboard input buffer, KBUF            ;
  303. ;                                        ;
  304. ;    Alters: All registers are altered                    ;
  305. ;                                        ;
  306. ;***************************************************************************;
  307. ;                                        ;
  308.  
  309. INSERT: STD            ; Reverse
  310.     MOV    AL,4        ; Number of digits in the number
  311.     SUB    AL,AH        ; Number of leading zeros to insert
  312. INS1:    MOV    DI,OFFSET KBUF+3 ; Destination address
  313.     MOV    SI,OFFSET KBUF+2 ; Source address
  314.     MOV    CX,3        ; Loop count
  315. INS2:    REP    MOVSB        ; Move three characters right one place
  316.     MOV    BYTE PTR [DI],'0'; Insert ASCII zero into left place
  317.     DEC    AL
  318.     JNZ    INS1        ; Loop for each zero to add
  319.     CLD            ; Forward
  320.     RET            ; Return to caller
  321.  
  322.     PAGE
  323. ;                                        ;
  324. ;***************************************************************************;
  325. ;                                        ;
  326. ;    Write CR LF To CRT                            ;
  327. ;                                        ;
  328. ;    Alters: All registers are altered                    ;
  329. ;                                        ;
  330. ;***************************************************************************;
  331. ;                                        ;
  332.  
  333. CRLF:    MOV    SI,OFFSET CRLFM ; Address of 'CR,LF'
  334.     XOR    AX,AX        ; Same row & column
  335.     CALL    WRITE        ; Write CR, LF
  336.     RET            ; Return to continue
  337. CRLFM    DB    CR,LF,'$'
  338.  
  339.  
  340. ;                                        ;
  341. ;***************************************************************************;
  342. ;                                        ;
  343. ;    HIDECUR - Hide The Cursor Off-Screen                    ;
  344. ;                                        ;
  345. ;    Alters: All registers except DI, SI & ES are altered            ;
  346. ;                                        ;
  347. ;***************************************************************************;
  348. ;                                        ;
  349.  
  350. HIDECUR:
  351.     PUSH    DI        ; Save registers
  352.     PUSH    SI
  353.     PUSH    ES
  354.     MOV    DL,79
  355.     MOV    DH,26        ; Move cursor off the screen to hide it
  356.     CALL    CURSE
  357.     POP    ES
  358.     POP    SI
  359.     POP    DI
  360.     RET
  361.  
  362.     PAGE
  363. ;                                        ;
  364. ;***************************************************************************;
  365. ;                                        ;
  366. ;    Display The Selected Memory                        ;
  367. ;                                        ;
  368. ;    Entry:    Segadd = Segment to display from                ;
  369. ;        Stadd  = Offset to display from                 ;
  370. ;        Ascseg = ASCII code of segment                    ;
  371. ;        Ascadd = ASCII code of offset                    ;
  372. ;                                        ;
  373. ;    Alters: All registers are altered                    ;
  374. ;                                        ;
  375. ;***************************************************************************;
  376. ;                                        ;
  377.  
  378. DISPLA: PUSH    OFFADD        ; Save starting offset
  379.     PUSH    ES        ; Save ES register
  380.     MOV    SI,OFFSET SEGO    ; "Seg  Off" string
  381.     MOV    AX,1        ; Left end of same line
  382.     CALL    WRITE        ; Output text
  383.  
  384. ;  Output the top line - hex display on left of screen
  385.  
  386.     MOV    CX,BYT        ; Number of bytes per line
  387.     MOV    AL,BYTE PTR OFFADD ; Get the low address byte
  388. LUP1:    PUSH    AX        ; Save for next output
  389.     CALL    HEX_ASC     ; Convert to ASCII
  390.     MOV    SI,OFFSET ASCTOP
  391.     MOV    BYTE PTR [SI],AH; Save low digit for output
  392.     XOR    AX,AX        ; Keep same line & column
  393.     CALL    WRITE        ; Write it to the display
  394.     POP    AX        ; Get previous digit
  395.     INC    AL        ; Increment for next digit
  396.     LOOP    LUP1        ; Repeat for the rest of the line
  397.     XOR    AX,AX        ; Same line & column
  398.     MOV    SI,OFFSET SPACE ; Follow with a blank
  399.     CALL    WRITE
  400.  
  401. ;  Output top line - ASCII display on right of screen
  402.  
  403.     MOV    CX,BYT        ; Number of bytes per line
  404.     MOV    AL,BYTE PTR OFFADD ; Get the low address byte
  405. LUP2:    PUSH    AX        ; Save for next output
  406.     CALL    HEX_ASC     ; Convert to ASCII
  407.     MOV    SI,OFFSET ASCTOP2
  408.     MOV    BYTE PTR [SI],AH; Store low digit for display later
  409.     XOR    AX,AX        ; Same row & column
  410.     CALL    WRITE        ; Write it on the display
  411.     POP    AX        ; Get previous digit
  412.     INC    AL        ; Increment for next digit
  413.     LOOP    LUP2        ; Repeat for the rest
  414.     CALL    CRLF        ; CR and LF
  415.  
  416.     MOV    BX,LINES    ; Number of lines to display
  417.     MOV    ES,SEGADD    ; Fetch segment to display
  418.  
  419. ;  Loop here for each line to display
  420.  
  421. LUP3:    PUSH    BX        ; Save line counter
  422.  
  423. ;  Output address at start of line
  424.  
  425. ;  Print the segment address on the left margin along with the offset
  426.  
  427.     MOV    SI,OFFSET SSTO    ; Point to the ASCII segment
  428.     MOV    AX,1        ; Left end of same line
  429.     CALL    WRITE        ; Display the segment
  430.     XOR    AX,AX        ; Print a colon between segment & offset
  431.     MOV    SI,OFFSET COLON
  432.     CALL    WRITE        ; Colon
  433.     MOV    AL,BYTE PTR OFFADD+1 ; Get the first address byte
  434.     CALL    HEX_ASC     ; Convert to ASCII
  435.     MOV    ASCADD,AX    ; Save for output to crt
  436.     MOV    AL,BYTE PTR OFFADD ; Get the second address byte
  437.     CALL    HEX_ASC     ; Convert it to ASCII too
  438.     MOV    ASCADD+2,AX    ; And save it also
  439.  
  440.     XOR    AX,AX
  441.     MOV    SI,OFFSET ASCADD; Display the offset
  442.     CALL    WRITE
  443.     MOV    SI,OFFADD    ; Get starting offset
  444.     ADD    OFFADD,BYT    ; Inc address by number of bytes in a line
  445.                 ;   for the offset on the next line
  446.  
  447. ;  Output one line of data (hex display on left and ASCII display on right)
  448.  
  449.     MOV    CX,BYT        ; Number of bytes to display in a line
  450.     MOV    DI,OFFSET ASCCHAR ; Address of ASCII buffer (right end of crt)
  451.  
  452. LUP4:    MOV    AL,ES:[SI]    ; Pick up next memory byte to display
  453.     PUSH    SI        ; Save this memory pointer
  454.     PUSH    AX        ; Save memory byte
  455.     CMP    AL,7FH        ; See if it can be displayed on crt
  456.     JGE    DASC1        ; Branch if not
  457.     CMP    AL,20H
  458.     JGE    DASC2        ; Branch if yes
  459. DASC1:    MOV    AL,'.'        ; Substitute period
  460. DASC2:    MOV    [DI],AL     ; Store for later display
  461.     POP    AX        ; Retrieve memory byte
  462.     CALL    HEX_ASC     ; Convert it to two ASCII codes
  463.     MOV    CHARS,AX    ; Store them for the hex display
  464.     XOR    AX,AX
  465.     MOV    SI,OFFSET CHARS ; We stored the data here
  466.     CALL    WRITE        ; Display the hex data
  467.     POP    SI        ; Get last memory pointer
  468.     INC    SI        ; Increment for next memory pointer
  469.     INC    DI        ; Increment ASCII buffer pointer
  470.     LOOP    LUP4        ; Repeat until done with this line
  471.  
  472.     XOR    AX,AX        ; Spaces between hex display & ASCII display
  473.     MOV    SI,OFFSET SPACES
  474.     CALL    WRITE
  475.  
  476. ;    Output ASCII display on right of crt
  477.  
  478. ;  Can't write this as a string because there might be a '$' symbol in it
  479.  
  480.     MOV    DI,NXT_POS    ; Next position on display screen
  481.     MOV    SI,OFFSET ASCCHAR ; Point to the symbol to display
  482.     MOV    ES,SEGADD
  483.     MOV    CX,BYT        ; Number of symbols to display
  484. LUP5:    PUSH    ES        ; Save our memory segment to display from
  485.     LODSB            ; Next symbol to display
  486.     MOV    ES,SCREEN    ; Fetch display segment
  487.     CALL    WRITE_ONE    ; Display the symbol
  488.     INC    DI        ; Skip past the attribute byte
  489.     POP    ES        ; Get the segment to get data from
  490.     LOOP    LUP5        ; Repeat for all symbols
  491.  
  492.     CALL    CRLF        ; Output CR and LF
  493.     POP    BX        ; Restore line counter
  494.     DEC    BX        ; Decrement line counter
  495.     JZ    DISEND
  496.     JMP    LUP3        ; Repeat for all lines
  497.  
  498. DISEND: POP    ES        ; Restore ES register
  499.     POP    OFFADD        ; Restore starting offset
  500.     RET            ; Return to calling routine
  501.  
  502.     PAGE
  503. ;                                        ;
  504. ;***************************************************************************;
  505. ;                                        ;
  506. ;    Keyboard Input Subroutine     Version 2/19/84                ;
  507. ;                                        ;
  508. ;    This routine reads ASCII codes from the keyboard into a buffer        ;
  509. ;                                        ;
  510. ;    Entry:    AH = Max number of characters to read excluding any CR code ;
  511. ;        DI = FWA of the buffer in which to store the characters     ;
  512. ;                                        ;
  513. ;    Exit:    AL = The last character read excluding any cr code        ;
  514. ;        AH = The number of characters read excluding BS or CR codes ;
  515. ;        DI = address of the last character read             ;
  516. ;             One less than buffer FWA if only CR is received        ;
  517. ;                                        ;
  518. ;    Backspace and carriage return codes are processed by DOS        ;
  519. ;                                        ;
  520. ;    The buffer must have the first two bytes available for storage of   ;
  521. ;    the max number of characters to read and number of characters read  ;
  522. ;    including the carriage return code                    ;
  523. ;                                        ;
  524. ;    Alters: All registers except BX are altered                ;
  525. ;                                        ;
  526. ;***************************************************************************;
  527. ;                                        ;
  528.  
  529. KYBD:    PUSH    BX        ; Save register
  530.     PUSH    DI        ; Save buffer address
  531.     INC    AH        ; Allow for the CR code
  532.     MOV    [DI],AH     ; Store max number of words to read
  533.     MOV    AX,0C0AH    ; Clear and read keyboard buffer
  534.     MOV    DX,DI        ; Buffer address in DX
  535.     INT    21H        ; Call DOS
  536.     POP    DI        ; Get buffer address
  537.     INC    DI
  538.     MOV    AH,[DI]     ; Get number of characters read
  539.     MOV    BL,AH        ; Put in base register
  540.     XOR    BH,BH
  541.     ADD    DI,BX        ; Set DI to last character position
  542.     MOV    AL,[DI]     ; Get last character read
  543.     POP    BX        ; Restore register
  544.     RET            ; Return to calling routine
  545.  
  546.     PAGE
  547. ;                                        ;
  548. ;***************************************************************************;
  549. ;                                        ;
  550. ;    Convert ASCII To Hex            Version 3/24/84            ;
  551. ;                                        ;
  552. ;        Modified to allow lower case 'a' thru 'f'            ;
  553. ;                                        ;
  554. ;    Convert two ASCII codes in AX to one hex number in AL            ;
  555. ;                                        ;
  556. ;    Entry:    AL = upper ASCII code                        ;
  557. ;        AH = lower ASCII code                        ;
  558. ;        Inputs must be '0' - '9', 'A' - 'F' or 'a' - 'f'        ;
  559. ;                                        ;
  560. ;    Exit:    AL = one hex number  (two hex digits, 0 - 9, A - F)        ;
  561. ;        Carry flag is set if an illegal hex digit is in the input   ;
  562. ;                                        ;
  563. ;    Alters: Registers AL and AH are altered                 ;
  564. ;                                        ;
  565. ;    Note:    Valid for all hex numbers 00 to FF                ;
  566. ;                                        ;
  567. ;***************************************************************************;
  568. ;                                        ;
  569.  
  570. ASC_HEX:PUSH    BX        ; Save registers
  571.     MOV    BX,AX        ; Save the ASCII codes
  572.     CALL    CNVRT1        ; Returns upper digit in lower AL
  573.     SHL    AL,1        ; Put it in upper AL
  574.     SHL    AL,1
  575.     SHL    AL,1
  576.     SHL    AL,1
  577.     XCHG    AL,BH        ; Save in BH & get lower digit
  578.     CALL    CNVRT1        ; Returns lower digit in lower AL
  579.     OR    AL,BH        ; Combine both hex digits into AL
  580.     POP    BX        ; Restore registers
  581.     CLC            ; Clear carry/error flag 
  582.     RET            ; Return to calling routine
  583.  
  584. CNVRT1: SUB    AL,30H        ; Partial conversion
  585.     JL    CERR        ; Al < 0 => illegal hex code
  586.  
  587. ;    Allow lower case alpha input if legal hex
  588.  
  589.     CMP    AL,9        ; Check for 0 - 9
  590.     JLE    CEND        ; Al <= 9 => 0 - 9
  591.     AND    AL,0DFH     ; Force capital letters of A thru F
  592.     CMP    AL,11H        ; Check for A - F
  593.     JL    CERR        ; Al < 11h => Illegal (between '9' and 'A')
  594.     SUB    AL,7        ; Convert A - F
  595.     CMP    AL,0FH        ; Al > 0fh => Illegal
  596.     JG    CERR        ; Error exit
  597. CEND:    RET            ; Return to continue
  598.  
  599. CERR:    POP    AX        ; Erase first return address
  600.     SUB    AX,AX        ; Set result to zero
  601.     POP    BX        ; Adjust stack
  602.     STC            ; Set carry/error flag 
  603.     RET            ; Return to calling routine
  604.  
  605.     PAGE
  606. ;                                         ;
  607. ;****************************************************************************;
  608. ;                                         ;
  609. ;    Convert Hex To ASCII          Version 8/07/84             ;
  610. ;                                         ;
  611. ;    Convert from two hex digits in AL to two ASCII codes in AX         ;
  612. ;                                         ;
  613. ;    Entry:    AL = Hex number 00H to FFH                     ;
  614. ;                                         ;
  615. ;    Exit:    AL = Upper ASCII code                         ;
  616. ;        AH = Lower ASCII code                         ;
  617. ;                                         ;
  618. ;    Alters: registers AL and AH are altered                  ;
  619. ;                                         ;
  620. ;    Note:    This conversion is valid for all hex codes             ;
  621. ;                                         ;
  622. ;****************************************************************************;
  623. ;                                         ;
  624.  
  625. HEX_ASC:
  626.     MOV    AH,AL        ; Save upper hex digit
  627.     CALL    CVRT2        ; Convert hex lower digit
  628.     XCHG    AH,AL        ; Save it in AH / get upper digit to convert
  629.     SHR    AL,1        ; Shift into low nibble
  630.     SHR    AL,1
  631.     SHR    AL,1
  632.     SHR    AL,1        ; Convert upper hex digit
  633.  
  634. ;  Convert one hex digit in lower nibble of AL into one ASCII code in AL
  635.  
  636. CVRT2:    AND    AL,0FH        ; Separate out one hex digit
  637.     ADD    AL,90H        ;   And convert
  638.     DAA            ;     To one
  639.     ADC    AL,40H        ;    ASCII code
  640.     DAA            ;      In AL
  641. CVRT4:    RET            ; Return to calling routine
  642.  
  643.     PAGE
  644. ;                                        ;
  645. ;***************************************************************************;
  646. ;                                        ;
  647. ;    Display Current Segment And Offset                    ;
  648. ;                                        ;
  649. ;    Entry:    None                                ;
  650. ;                                        ;
  651. ;    Exit:    None                                ;
  652. ;                                        ;
  653. ;    Alters: registers AX, DX and SI are altered                ;
  654. ;                                        ;
  655. ;***************************************************************************;
  656. ;                                        ;
  657.  
  658. DSEGOFF:
  659.     MOV    AL,BYTE PTR SEGADD+1 ; Get the first segment byte
  660.     CALL    HEX_ASC     ; Convert to ASCII
  661.     MOV    SSTO,AX     ; Save for output to crt
  662.     MOV    AL,BYTE PTR SEGADD ; Get the second segment byte
  663.     CALL    HEX_ASC     ; Convert it to ASCII too
  664.     MOV    SSTO[2],AX    ; And save it also
  665.  
  666.     MOV    AL,BYTE PTR OFFADD+1 ; Get the first offset byte
  667.     CALL    HEX_ASC     ; Convert to ASCII
  668.     MOV    OFFSTO,AX    ; Save for output to crt
  669.     MOV    AL,BYTE PTR OFFADD ; Get the second segment byte
  670.     CALL    HEX_ASC     ; Convert it to ASCII too
  671.     MOV    OFFSTO[2],AX    ; And save it also
  672.  
  673.     MOV    SI,OFFSET CURSEG; Display segment
  674.     MOV    AH,11        ; Line no.
  675.     MOV    AL,1        ; Left end of line
  676.     CALL    WRITE
  677.     MOV    SI,OFFSET CUROFF; Display offset
  678.     XOR    AX,AX        ; Keep current line and column
  679.     CALL    WRITE
  680.     CALL    DISPLIN
  681.     RET
  682.  
  683. ;                                        ;
  684. ;***************************************************************************;
  685. ;                                        ;
  686. ;    Display A Line Of Underscores                        ;
  687. ;                                        ;
  688. ;    Entry:    None                                ;
  689. ;                                        ;
  690. ;    Exit:    None                                ;
  691. ;                                        ;
  692. ;    Alters: None                                ;
  693. ;                                        ;
  694. ;***************************************************************************;
  695. ;                                        ;
  696.  
  697. UL    DB    CR,LF,79 DUP('_'),'$'
  698.  
  699. DISPLIN:
  700.     PUSH    CX        ; Save registers
  701.     PUSH    BX
  702.     PUSH    AX
  703.     MOV    AX,1        ; Left end of current row
  704.     MOV    SI,OFFSET UL
  705.     CALL    WRITE
  706.     POP    AX        ; Restore registers
  707.     POP    BX
  708.     POP    CX
  709.     RET
  710.  
  711.     PAGE
  712. ;                                         ;
  713. ;****************************************************************************;
  714. ;                                         ;
  715. ;    FIND a HEX string in memory                         ;
  716. ;                                         ;
  717. ;    FIND a string in memory starting from the current segment & offset+1 ;
  718. ;                                         ;
  719. ;    Entry:    SEGADD = Starting segment where search starts             ;
  720. ;        OFFADD = Starting offset - 1 where search starts         ;
  721. ;                                         ;
  722. ;    Exit:    SEGADD = Segment where the string was found             ;
  723. ;        OFFADD = Starting offset of the string if found          ;
  724. ;                                         ;
  725. ;    Alters: All registers are altered                     ;
  726. ;        SEGADD & OFFADD are altered if the string is found         ;
  727. ;        The hex and ASCII displays will be shown on the CRT if found ;
  728. ;                                         ;
  729. ;****************************************************************************;
  730. ;                                         ;
  731.  
  732. FINDIT: MOV    AH,15        ; Line number
  733.     MOV    AL,1        ; Column number
  734.     MOV    SI,OFFSET FINDMSG
  735.     CALL    WRITE        ; Display the prompt
  736.     MOV    DH,17        ; Position cursor in the prompt
  737.     MOV    DL,23
  738.     MOV    DI,OFFSET KBUF    ; Where to store the ASCII bytes
  739.     MOV    WORD PTR SRCHCNT,0 ; Clear the count of symbols entered
  740.  
  741. ;  Loop here for each byte
  742.  
  743. FIN2:    PUSH    DX        ; Save cursor position
  744.     CALL    CURSE        ; Position the cursor at right end of prompt
  745.  
  746. ;  Loop here for each symbol or digit
  747.  
  748.     MOV    BL,0        ; Start with toggle = 0
  749.  
  750. FIN4:    MOV    AX,0C01H    ; Wait for any key to be pressed
  751.     INT    21H        ; Read the ASCII code
  752.  
  753. ;  Check for valid input
  754.  
  755.     CMP    AL,CR        ; Go do the search if CR key
  756.     JE    FIN5
  757.  
  758.     CMP    AL,BS        ; Check for backspace
  759.     JE    FIN8
  760.     CMP    AL,0
  761.     JNZ    FIN6        ; Quit if extended code
  762. FIN5:    JMP    FIN15
  763.  
  764. FIN6:    CMP    AL,'0'        ; Verify legal hex digit
  765.     JL    FIN7
  766.     CMP    AL,'9'
  767.     JLE    FIN13
  768.     AND    AL,0DFH     ; Force capital letters
  769.     CMP    AL,'F'
  770.     JG    FIN7
  771.     CMP    AL,'A'
  772.     JGE    FIN13        ; Skip if valid hex digit
  773.  
  774. ;  Illegal symbol input
  775.  
  776. FIN7:    MOV    DL,7        ; Beep, illegal input
  777.     MOV    AH,2
  778.     INT    21H
  779.     POP    DX        ; Cursor position
  780.     PUSH    DX
  781.     CALL    CURSE        ; Move cursor back to where it was
  782.  
  783.     MOV    DL,'_'        ; Redisplay underline
  784.     MOV    AH,2
  785.     INT    21H
  786.     JMP    SHORT FIN10    ; Skip to continue
  787.  
  788. ;  Backspace
  789.  
  790. FIN8:    DEC    DI        ; Decrement buffer location after backspace
  791.     CMP    DI,OFFSET KBUF
  792.     JGE    FIN11        ; Branch if not left end of buffer
  793.     MOV    DI,OFFSET KBUF
  794.     MOV    DL,7        ; Beep, illegal input at left end of buffer
  795.     MOV    AH,2
  796.     INT    21H
  797.     DEC    WORD PTR SRCHCNT
  798.  
  799. ;  Backspace or Illegal symbol
  800.  
  801. FIN10:    POP    DX        ; Get cursor position
  802.     PUSH    DX
  803.     CALL    CURSE        ; Restore cursor
  804.     JMP    FIN4        ; Loop for next input
  805.  
  806. ;  Backspace and not at left end of buffer
  807.  
  808. FIN11:    CMP    BL,0        ; Check whether first or second digit of byte
  809.     JNZ    FIN12        ; Skip if toggle is not 0
  810.     POP    DX        ; Cursor position
  811.     DEC    DL        ; Dec cursor position
  812.     PUSH    DX        ; Save position
  813.     DEC    DL        ; Dec cursor position
  814.     CALL    CURSE        ; Move cursor left one
  815.  
  816. FIN12:    MOV    DL,'_'        ; Redisplay underline
  817.     MOV    AH,2
  818.     INT    21H
  819.     POP    DX
  820.     DEC    DL        ; Dec cursor position
  821.     PUSH    DX
  822.     CALL    CURSE        ; Move cursor left one
  823.     XOR    BL,1        ; Change toggle after backing up
  824.     JMP    FIN4        ; Loop for next input
  825.  
  826. FIN13:    XOR    BL,1        ; Change toggle after symbol input
  827.     STOSB            ; Store the ASCII code in the keyboard buffer
  828.     INC    WORD PTR SRCHCNT
  829.     POP    DX        ; Cursor position
  830.     INC    DL        ; Bump cursor position
  831.     PUSH    DX        ; Save new position
  832.     CMP    BL,0
  833.     JZ    FIN14
  834.     JMP    FIN4        ; Repeat for second digit
  835.  
  836. FIN14:    POP    DX        ; Get cursor position
  837.     INC    DL        ; Move cursor position to next byte
  838.  
  839.     CMP    DI,OFFSET KBUF+8
  840.     JGE    FIN16        ; Branch to do the search
  841.     JMP    FIN2        ; Loop for another symbol
  842.  
  843. FIN15:    POP    DX        ; Adjust stack
  844.     CMP    AL,0
  845.     JNE    FIN16
  846.     JMP    FIN30        ; Quit if extended code
  847.  
  848. ;  Convert the inputs to hex for the search
  849.  
  850. FIN16:    CALL    CLRSCRN     ; Clear bottom of the screen
  851.     CALL    HIDECUR     ; Hide the cursor
  852.  
  853.     MOV    CX,SRCHCNT    ; Number of digits or symbols entered
  854.     SHR    CX,1        ; Number of hex bytes
  855.     JCXZ    FIN30        ; Quit if invalid - only 1 digit
  856.     MOV    SI,OFFSET KBUF    ; Point to the ASCII string of bytes
  857.     MOV    DI,OFFSET SRCHCHR ; Destination
  858. FIN17:    LODSW
  859.     CALL    ASC_HEX     ; Convert to one hex byte
  860.     STOSB
  861.     LOOP    FIN17        ; Loop for all bytes
  862.  
  863. ;  Now search from current SEG:OFF for the string of bytes just entered
  864.  
  865. FIN18:    PUSH    ES        ; Save ES segment
  866.     MOV    DI,OFFADD    ; Current offset
  867.     INC    DI        ; Start at the NEXT location
  868.     MOV    AX,SEGADD    ; Get starting segment to search
  869.     DEC    AX
  870.     MOV    ES,AX        ; Put first seg - 1 in ES
  871.     CMP    AX,0FFFFH
  872.     JNE    FIN20        ; Skip if not starting with segment zero
  873.     INC    AX
  874.     JMP    SHORT FIN22    ; Skip check for zero if starting at zero
  875.  
  876. ;  Start searching a new segment for the string. Quit after Segment FFFFH
  877.  
  878. FIN20:    MOV    AX,ES        ; Get the previous segment
  879.     INC    AX        ; Step to next segment to scan
  880.     OR    AX,AX
  881.     JNZ    FIN22        ; Skip over "Not Found message
  882.  
  883.     MOV    AH,18        ; Line number
  884.     MOV    AL,36        ; Column number
  885.     MOV    SI,OFFSET NOTFND
  886.     CALL    WRITE        ; Display the prompt
  887.     MOV    DL,7        ; Beep
  888.     MOV    AH,2
  889.     INT    21H
  890.  
  891.     MOV    AL,12        ; Delay so message can be seen
  892.     XOR    CX,CX
  893.     LOOP    $
  894.     DEC    AL
  895.     JNZ    $-4
  896.     JMP    SHORT FIN29    ; Quit at end of memory
  897.  
  898. ;  Repeat Find Entry Point
  899.  
  900. REP_FIND:
  901.     PUSH    ES
  902.     CALL    HIDECUR     ; Hide the cursor
  903.  
  904. FIN22:    MOV    ES,AX        ; Put the segment in ES
  905.  
  906. ;  Search for the first character in the string for a starting point
  907.  
  908.     MOV    CX,16
  909.     MOV    AL,SRCHCHR    ; First hex byte in the string
  910.     REPNE    SCASB
  911.     JE    FIN24        ; Found the first symbol so go check for more
  912.     SUB    DI,DI        ; Offset is 0 for the rest of the segments
  913.     JMP    SHORT FIN20    ; Loop to get the next segment
  914.  
  915. ;  Search for the string
  916.  
  917. FIN24:    DEC    DI        ; Point to the first symbol we just found
  918.     MOV    SI,OFFSET SRCHCHR ; Point to first symbol of string to find
  919.     MOV    CX,SRCHCNT    ; Length of string to find
  920.     SHR    CX,1
  921.     REPE    CMPSB        ; 
  922.     JE    FIN28        ; Found it so skip to display it
  923.     SUB    DI,DI        ; Offset is 0 for the rest of the segments
  924.     JMP    SHORT FIN20    ; Loop to get the next segment
  925.     
  926. FIN28:    MOV    AX,SRCHCNT
  927.     SHR    AX,1
  928.     SUB    DI,AX        ; Point to the start of the string we found
  929.     MOV    SEGADD,ES    ; Save the segment where it was found
  930.     MOV    OFFADD,DI
  931.  
  932. FIN29:    POP    ES        ; Restore ES segment
  933. FIN30:    RET            ; Return to calling routine
  934.  
  935.     .XLIST
  936.     SUBTTL    Video & Display Subroutines
  937.     .LIST
  938.  
  939. CGA    EQU    0B800H        ; Screen segment - color/graphics
  940. MONO    EQU    0B000H        ; Screen segment - b & w adapter
  941.  
  942. CGAFLG    DB    0        ; 1 = CGA, 0 = MONO (default)
  943. SCREEN    DW    0        ; Base segment of display screen
  944. RET_ADD DW    0        ; Address of Horizontal Retrace Status Register
  945.  
  946. VMODE    DB    0        ; Original video mode
  947. VCOL    DB    0        ; Original number of video columns
  948. VPAGE    DB    0        ; Original active video page
  949. CURSIZE DW    0        ; Original cursor size or lines
  950.  
  951.  
  952. ;                                        ;
  953. ;***************************************************************************;
  954. ;                                        ;
  955. ;    Init - Initialize Screen Routines                    ;
  956. ;                                        ;
  957. ;    Entry:    None                                ;
  958. ;                                        ;
  959. ;    Exit:    None                                ;
  960. ;                                        ;
  961. ;    Alters: All registers except ES are altered                ;
  962. ;                                        ;
  963. ;***************************************************************************;
  964. ;                                        ;
  965.  
  966. ;    Init - Get Horizontal Retrace Status Register Address            ;
  967.  
  968. FLAG_SEG  EQU    40H        ; Segment containing DOS flags
  969. VID_BASE  EQU    63H        ; Location of base address of video controller
  970.  
  971. INIT:    PUSH    ES        ; Save ES
  972.     MOV    AX,FLAG_SEG    ; Segment containing DOS flags
  973.     MOV    ES,AX
  974.     MOV    AX,ES:VID_BASE    ; Get base address of video controller
  975.     ADD    AX,6        ; Horizontal Retrace Status Register Address
  976.     MOV    RET_ADD,AX    ; Save it
  977.  
  978. ;  Get base address of the display screen
  979.  
  980.     MOV    WORD PTR SCREEN,MONO; Screen base for mono
  981.     INT    11H        ; Get hardware flags.
  982.     TEST    AX,10H        ; See if we have a cga or monochrome
  983.     JNZ    INIT2        ; Skip if mono display
  984.     MOV    WORD PTR SCREEN,CGA; Screen base for cga
  985.     MOV    BYTE PTR CGAFLG,1   ; Set flag for cga
  986.  
  987. ;  Get current video mode
  988.  
  989. INIT2:    MOV    AH,15
  990.     INT    10H        ; Get current video mode & save it
  991.     MOV    VMODE,AL    ; Current video mode
  992.     MOV    VCOL,AH     ; Number of columns
  993.     MOV    VPAGE,BH    ; Current active video page
  994.  
  995.     MOV    AH,3
  996.     INT    10H        ; Get cursor type or size
  997.     MOV    CURSIZE,CX    ; Save it to be restored at end
  998.  
  999. ;  Select video mode 3, 80x25 color, alpha if CGA or mode 7 if MONO adapter
  1000.  
  1001.     MOV    AX,3        ; Select video mode 3
  1002.     CMP    BYTE PTR CGAFLG,0 ; 1 = CGA, 0 = MONO
  1003.     JNZ    INIT4        ; Branch if CGA
  1004.     MOV    AL,7        ; Select video mode 7
  1005. INIT4:    INT    10H
  1006.  
  1007. ;  Select active page 0
  1008.  
  1009.     MOV    AX,500H     ; Select active page 0
  1010.     INT    10H
  1011.     POP    ES
  1012.  
  1013. ;  Delay to try to prevent the "screen jump" before writing to it
  1014.  
  1015.     MOV    AL,3
  1016.     XOR    CX,CX
  1017. INIT5:    LOOP    INIT5
  1018.     DEC    AL
  1019.     JNZ    INIT5
  1020.  
  1021.     RET
  1022.  
  1023. ;                                        ;
  1024. ;***************************************************************************;
  1025. ;                                        ;
  1026. ;    CURSE - Position Cursor Routine                     ;
  1027. ;                                        ;
  1028. ;    Place the block cursor at DH, DL (Row, Column - 0,0 is upper left)  ;
  1029. ;                                        ;
  1030. ;    Entry:    None                                ;
  1031. ;                                        ;
  1032. ;    Exit:    None                                ;
  1033. ;                                        ;
  1034. ;    Alters: All registers are altered except AX & DX            ;
  1035. ;                                        ;
  1036. ;***************************************************************************;
  1037. ;                                        ;
  1038.  
  1039. CURSE:    PUSH    AX        ; Save registers
  1040.     PUSH    BX
  1041.  
  1042.     MOV    AH,2        ; Set cursor position
  1043.     MOV    BH,VPAGE    ; Our video page
  1044.     INT    10H
  1045.  
  1046.     MOV    AH,1        ; Set cursor size
  1047.     MOV    CX,7        ; Starting line 0, ending line 7
  1048.     INT    10H
  1049.  
  1050.     POP    BX        ; Restore registers
  1051.     POP    AX
  1052.     RET
  1053.  
  1054. ;                                        ;
  1055. ;***************************************************************************;
  1056. ;                                        ;
  1057. ;    Reset The Original Video Mode And Cursor Size                ;
  1058. ;                                        ;
  1059. ;                                        ;
  1060. ;    Entry:    None                                ;
  1061. ;                                        ;
  1062. ;    Exit:    None                                ;
  1063. ;                                        ;
  1064. ;    Alters: All registers are altered                    ;
  1065. ;                                        ;
  1066. ;***************************************************************************;
  1067. ;                                        ;
  1068.  
  1069. RESET:    MOV    AH,0
  1070.     MOV    AL,VMODE    ; Restore original video mode
  1071.     INT    10H
  1072.  
  1073.     MOV    AH,5
  1074.     MOV    AL,VPAGE    ; Restore original video page
  1075.     INT    10H
  1076.  
  1077.     MOV    AH,1        ; Restore original cursor size
  1078.     MOV    CX,CURSIZE    ; Get original cursor size
  1079.     INT    10H
  1080.  
  1081.     RET
  1082.  
  1083.     PAGE
  1084. ;                                        ;
  1085. ;***************************************************************************;
  1086. ;                                        ;
  1087. ;    WRITE an ASCII String On The Display                    ;
  1088. ;                                        ;
  1089. ;    Entry:                                    ;
  1090. ;        AH = Line number   (1 - 24) (if 0, start at current position)   ;
  1091. ;        AL = Char position (1 - 80) (if 0, start at current position)   ;
  1092. ;        SI = Offset address of the string                    ;
  1093. ;        The string must be terminated with a '$'                ;
  1094. ;                                        ;
  1095. ;    Exit:                                    ;
  1096. ;        AH points to the start of the next line                ;
  1097. ;        AL points to the next char position in the line            ;
  1098. ;        NXT_POS contains the next screen offset                ;
  1099. ;                                        ;
  1100. ;    Alters: All registers except AX & SI are preserved            ;
  1101. ;                                        ;
  1102. ;***************************************************************************;
  1103. ;                                        ;
  1104.  
  1105. LINE    EQU    160        ; Number of bytes per display line
  1106. MLINE    EQU    14        ; Highest line to use for text messages
  1107.  
  1108. LINENO    DB    0        ; Current line number-1
  1109. CHARPOS DW    0        ; Current character position-1
  1110.  
  1111. WRITE:    PUSH    DI        ; Save registers
  1112.     PUSH    CX
  1113.     PUSH    ES
  1114.     MOV    ES,SCREEN    ; Get screen segment
  1115.  
  1116.     OR    AH,AH        ; 0 = Use pre-selected display line
  1117.     JZ    W1        ; Keep same line number
  1118.     DEC    AH        ; Make line index of 0 - 23
  1119.     JL    W8        ; Quit if too small
  1120.     CMP    AH,23
  1121.     JG    W8        ; Quit if too big
  1122.     MOV    LINENO,AH    ; Save line # -1
  1123.  
  1124. W1:    DEC    AL
  1125.     JL    W2        ; Neg = use pre-selected column number
  1126.     MOV    BYTE PTR CHARPOS,AL; Save position -1
  1127. W2:    MOV    AH,LINENO    ; Get line number-1
  1128.     MOV    AL,LINE     ; Number of bytes in a line
  1129.     MUL    AH        ; Offset = (line-1) * (bytes per line)
  1130.     MOV    DI,AX        ; Starting offset of the line in DI
  1131.     ADD    DI,CHARPOS    ; Add for starting position within the line
  1132.     ADD    DI,CHARPOS    ; Add to account for the attribute
  1133.     MOV    CX,80        ; Max length of a line
  1134.     SUB    CX,CHARPOS    ; Number characters to end of line
  1135.  
  1136. W3:    LODSB            ; Get next character of message
  1137.     CMP    AL,'$'        ; Finished if '$'
  1138.     JE    W8        ; Skip when finished
  1139.  
  1140.     CMP    AL,CR
  1141.     JNE    W4
  1142.     MOV    WORD PTR CHARPOS,0
  1143.     JMP    SHORT W2    ; Restart this line after CR
  1144.  
  1145. W4:    CMP    AL,LF
  1146.     JNE    W5        ; Skip if not LF
  1147.  
  1148.     ADD    DI,LINE     ; Move down one line after LF
  1149.     INC    BYTE PTR LINENO
  1150.     JMP    SHORT W3    ; Loop back without decrementing counter
  1151.  
  1152. W5:    CALL    WRITE_ONE    ; Write this character on screen
  1153.     INC    DI        ; Skip past attribute byte    
  1154.     MOV    NXT_POS,DI    ; Save next screen offset position
  1155.     INC    WORD PTR CHARPOS; Bump the column
  1156.     CMP    WORD PTR CHARPOS,80
  1157.     JLE    W6
  1158.     MOV    WORD PTR CHARPOS,0
  1159.  
  1160. W6:    LOOP    W3        ; Repeat for the rest of the line
  1161.  
  1162.     INC    BYTE PTR LINENO
  1163.     JMP    SHORT W1    ; Repeat for the rest of the lines
  1164.  
  1165. W8:    POP    ES        ; Restore the registers
  1166.     POP    CX
  1167.     POP    DI
  1168.     RET            ; Return to calling routine
  1169.  
  1170. ;                                        ;
  1171. ;***************************************************************************;
  1172. ;                                        ;
  1173. ;    WRITE_ONE Character To The Display                    ;
  1174. ;                                        ;
  1175. ;    Entry:    Al = Character to write on the display screen            ;
  1176. ;        DI = Offset into the display screen                ;
  1177. ;        ES = Screen segment                        ;
  1178. ;                                        ;
  1179. ;    Exit:    DI is incremented by one before exit                ;
  1180. ;                                        ;
  1181. ;    Alters: Register DX is altered                        ;
  1182. ;                                        ;
  1183. ;    There is only time to write one (1) symbol during the horizontal    ;
  1184. ;    retrace without creating any snow.                    ;
  1185. ;                                        ;
  1186. ;***************************************************************************;
  1187. ;                                        ;
  1188.  
  1189. WRITE_ONE:
  1190.     PUSH    AX        ; Save registers
  1191.     PUSH    BX
  1192.     MOV    BL,AL        ; Save the character to write
  1193.     MOV    DX,RET_ADD    ; Address of status register
  1194.  
  1195. W_ONE1: IN    AL,DX        ; Read horizontal retrace status
  1196.     SHR    AL,1        ; Shift bit zero into carry bit
  1197.     JC    W_ONE1        ; Wait for end of horizontal retrace
  1198.  
  1199.     CLI            ; Disable interrupts during write to screen
  1200. W_ONE2: IN    AL,DX        ; Read horizontal retrace status
  1201.     SHR    AL,1
  1202.     JNC    W_ONE2        ; Wait for start of horizontal retrace
  1203.  
  1204.     MOV    ES:[DI],BL    ; Write the character on the display
  1205.  
  1206.     STI            ; Enable interrupts after screen write
  1207.     INC    DI        ; Move pointer
  1208.     POP    BX        ; Restore registers
  1209.     POP    AX
  1210.     RET
  1211.  
  1212. ;                                        ;
  1213. ;***************************************************************************;
  1214. ;                                        ;
  1215. ;    CLRSCRN - Clear The Screen From "MLINE" Through Line 24         ;
  1216. ;                                        ;
  1217. ;    Entry:    None                                ;
  1218. ;                                        ;
  1219. ;    Exit:    None                                ;
  1220. ;                                        ;
  1221. ;    Alters: Register DX is altered                        ;
  1222. ;                                        ;
  1223. ;***************************************************************************;
  1224. ;                                        ;
  1225.  
  1226. CLRSCRN:
  1227.     PUSH    AX        ; Save registers
  1228.     PUSH    CX
  1229.     PUSH    DI
  1230.     PUSH    ES
  1231.  
  1232.     MOV    CX,(26-MLINE)*LINE/2 ; Number of characters to erase
  1233.     MOV    DI,(MLINE-1)*LINE    ; Initial offset into display screen
  1234.  
  1235.     CMP    BYTE PTR CGAFLG,0
  1236.     JZ    CLR1        ; Skip if mono
  1237.  
  1238. ;  Turn off the video
  1239.  
  1240.     MOV    DX,RET_ADD    ; Status register address (03DA hex)
  1241.     SUB    DX,2        ; Mode control register (03D8 hex)
  1242.     MOV    AL,1        ; 80X25 alpha color, video off
  1243.     OUT    DX,AL
  1244.  
  1245. CLR1:    MOV    AL,' '        ; Blank symbol
  1246.     MOV    ES,SCREEN    ; Set ES to screen segment
  1247. CLR2:    STOSB            ; Write one blank on the display
  1248.     INC    DI        ; Skip past attribute byte
  1249.     LOOP    CLR2        ; Loop for entire display
  1250.  
  1251.     CMP    BYTE PTR CGAFLG,0
  1252.     JZ    CLR3        ; Skip if MONO
  1253.  
  1254. ;  Turn on the video
  1255.  
  1256.     MOV    DX,RET_ADD    ; Status register address (03DA hex)
  1257.     SUB    DX,2        ; Mode control register   (03D8 hex)
  1258.     MOV    AL,9        ; 80X25 alpha color, video on
  1259.     OUT    DX,AL
  1260.  
  1261. CLR3:    POP    ES        ; Restore registers
  1262.     POP    DI
  1263.     POP    CX
  1264.     POP    AX
  1265.     RET            ; Return to calling routine
  1266.  
  1267.     .XLIST
  1268.     SUBTTL    Messages and Data Storage
  1269.     PAGE    +
  1270.     .LIST
  1271.  
  1272. ;  Messages And Data Storage
  1273.  
  1274. HELLO    DB    'LOOKMEM  Interactive Memory Display  Version 8/29/88$'
  1275.  
  1276. SEGO    DB    CR,LF,LF,'Seg  Off    $'
  1277.  
  1278. HELPMSG DB    'LOOKMEM Help : ',CR,LF
  1279.     DB    24,'    Displays the next 128 bytes',CR,LF
  1280.     DB    25,'    Displays the previous 128 bytes',CR,LF
  1281.     DB    16,'    Increments the current segment by 10H',CR,LF
  1282.     DB    17,'    Decrements the current segment by 10H',CR,LF
  1283.     DB    17,196,217,'  Specify new segments or offsets',CR,LF
  1284.     DB    'Esc  Exits from LOOKMEM to DOS',CR,LF
  1285.     DB    'F1   Displays this help text',CR,LF
  1286.     DB    'F2   Find a string from current seg:off',CR,LF
  1287.     DB    'F3   Find Next occurrence of same string',CR,LF,LF
  1288.     DB    '     Copyright (C) John Pulliam 1988',CR,LF
  1289.     DB    '     (press any key to continue)$'
  1290. LEN_HELP EQU    $ - 2 - OFFSET HELP
  1291.  
  1292. FINDMSG DB    'FIND a hex string of up to 4 bytes starting from '
  1293.     DB    'the currently',CR,LF,'displayed segment & offset',CR,LF,LF
  1294.     DB    'Enter the hex string : __ __ __ __$'
  1295.  
  1296. NOTFND    DB    'Not Found$'
  1297.  
  1298. CURSEG    DB    'Current Segment :  '
  1299. SSTO    DW    0,0
  1300.     DB    '$'
  1301.  
  1302. CUROFF    DB    '   Current Offset  :  '
  1303. OFFSTO    DW    0,0
  1304.     DB    '$'
  1305. SPACE    DB    ' $'
  1306. SPACES    DB    '  $'
  1307. SPACES4    DB    '    $'
  1308. COLON    DB    ':$'
  1309.  
  1310. USRPROM DB    'Press Esc, ',16,', ',17,', ',24,', ',25,','
  1311.     DB    ' F1 (help), F2 (find), F3 (find next), or ',17,196,217,' :$'
  1312. LEN_PROM EQU    $ - 1 - OFFSET USRPROM
  1313. BLANKS    DB    LEN_PROM + 1 DUP(' '),'$'
  1314.  
  1315. SEGMSG    DB    'Enter the segment address in hex  (',17,196,217,' for no '
  1316.     DB    'change) :     $'
  1317. LEN_SEGMSG EQU    $ - 6 - OFFSET SEGMSG
  1318.  
  1319. STMSG    DB    'Enter the offset  address in hex  (',17,196,217
  1320.     DB    ' for no change) :     $'
  1321. LEN_STMSG EQU    $ - 6 - OFFSET STMSG
  1322.  
  1323. ASCTOP    DB    '   $'        ; Buffer for top line of hex display
  1324. ASCTOP2 DB    ' $'        ; Buffer for top line of ASCII display
  1325.  
  1326. CHARS    DW    '  '        ; Buffer for hex display
  1327.     DB    ' $'
  1328.  
  1329. ASCCHAR DB    16 DUP(' ')    ; Buffer for ASCII display
  1330.  
  1331. NXT_POS DW    0        ; Next offset position in display
  1332.  
  1333. SEGADD    DW    0        ; Segment to display (hex)
  1334. ASCSEG    DW    0,0        ; Segment to display (ASCII)
  1335.     DB    '  $'
  1336.  
  1337. OFFADD    DW    0        ; Offset to display (hex)
  1338. ASCADD    DW    0,0        ; Offset to display (ASCII)
  1339.     DB    '  $'
  1340. KBUFSZ    DB    0,0        ; Keyboard input buffer
  1341. KBUF    DB    '        $'    ; Keyboard input data, 8 ASCII symbols
  1342. SRCHCNT DW    0
  1343. SRCHCHR DB    0,0,0,0
  1344.  
  1345.     CSEG    ENDS
  1346.     END    LOOKMEM
  1347.