mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-11-25 07:05:45 +00:00
694 lines
26 KiB
NASM
694 lines
26 KiB
NASM
TITLE PART1 DEBUGGER COMMANDS
|
||
|
||
; Routines to perform debugger commands except ASSEMble and UASSEMble
|
||
|
||
.xlist
|
||
.xcref
|
||
INCLUDE DEBEQU.ASM
|
||
INCLUDE DOSSYM.ASM
|
||
.cref
|
||
.list
|
||
|
||
CODE SEGMENT PUBLIC BYTE 'CODE'
|
||
CODE ENDS
|
||
|
||
CONST SEGMENT PUBLIC BYTE
|
||
|
||
EXTRN SYNERR:BYTE
|
||
|
||
EXTRN DISPB:WORD,DSIZ:BYTE,DSSAVE:WORD
|
||
if sysver
|
||
EXTRN CIN:DWORD,PFLAG:BYTE
|
||
endif
|
||
|
||
CONST ENDS
|
||
|
||
DATA SEGMENT PUBLIC BYTE
|
||
|
||
EXTRN DEFLEN:WORD,BYTEBUF:BYTE,DEFDUMP:BYTE
|
||
|
||
DATA ENDS
|
||
|
||
DG GROUP CODE,CONST,DATA
|
||
|
||
|
||
CODE SEGMENT PUBLIC BYTE 'CODE'
|
||
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
|
||
|
||
|
||
PUBLIC HEXCHK,GETHEX1,PRINT,DSRANGE,ADDRESS,HEXIN,PERROR
|
||
PUBLIC GETHEX,GET_ADDRESS,GETEOL,GETHX,PERR
|
||
PUBLIC PERR,MOVE,DUMP,ENTER,FILL,SEARCH,DEFAULT
|
||
if sysver
|
||
PUBLIC IN
|
||
EXTRN DISPREG:NEAR,DEVIOCALL:NEAR
|
||
endif
|
||
|
||
EXTRN OUT:NEAR,CRLF:NEAR,OUTDI:NEAR,OUTSI:NEAR,SCANP:NEAR
|
||
EXTRN SCANB:NEAR,BLANK:NEAR,TAB:NEAR,PRINTMES:NEAR,COMMAND:NEAR
|
||
EXTRN HEX:NEAR,BACKUP:NEAR
|
||
|
||
|
||
DEBCOM1:
|
||
|
||
; RANGE - Looks for parameters defining an address range.
|
||
; The first parameter is the starting address. The second parameter
|
||
; may specify the ending address, or it may be preceded by
|
||
; "L" and specify a length (4 digits max), or it may be
|
||
; omitted and a length of 128 bytes is assumed. Returns with
|
||
; segment in AX, displacement in DX, and length in CX.
|
||
|
||
DSRANGE:
|
||
MOV BP,[DSSAVE] ; Set default segment to DS
|
||
MOV [DEFLEN],128 ; And default length to 128 bytes
|
||
RANGE:
|
||
CALL ADDRESS
|
||
PUSH AX ; Save segment
|
||
PUSH DX ; Save offset
|
||
CALL SCANP ; Get to next parameter
|
||
MOV AL,[SI]
|
||
CMP AL,"L" ; Length indicator?
|
||
JE GETLEN
|
||
MOV DX,[DEFLEN] ; Default length
|
||
CALL HEXIN ; Second parameter present?
|
||
JC GetDef ; If not, use default
|
||
MOV CX,4
|
||
CALL GETHEX ; Get ending address (same segment)
|
||
MOV CX,DX ; Low 16 bits of ending addr.
|
||
POP DX ; Low 16 bits of starting addr.
|
||
SUB CX,DX ; Compute range
|
||
JAE DSRNG2
|
||
DSRNG1: JMP PERROR ; Negative range
|
||
DSRNG2: INC CX ; Include last location
|
||
JCXZ DSRNG1 ; Wrap around error
|
||
POP AX ; Restore segment
|
||
RET
|
||
GetDef:
|
||
POP CX ; get original offset
|
||
PUSH CX ; save it
|
||
NEG CX ; rest of segment
|
||
JZ RngRet ; use default
|
||
CMP CX,DX ; more room in segment?
|
||
JAE RngRet ; yes, use default
|
||
JMP RngRet1 ; no, length is in CX
|
||
|
||
GETLEN:
|
||
INC SI ; Skip over "L" to length
|
||
MOV CX,4 ; Length may have 4 digits
|
||
CALL GETHEX ; Get the range
|
||
RNGRET:
|
||
MOV CX,DX ; Length
|
||
RngRet1:
|
||
POP DX ; Offset
|
||
MOV AX,CX
|
||
ADD AX,DX
|
||
JNC OKRET
|
||
CMP AX,1
|
||
JAE DSRNG1 ; Look for wrap error
|
||
OKRET:
|
||
POP AX ; Segment
|
||
RET
|
||
|
||
DEFAULT:
|
||
; DI points to default address and CX has default length
|
||
CALL SCANP
|
||
JZ USEDEF ; Use default if no parameters
|
||
MOV [DEFLEN],CX
|
||
CALL RANGE
|
||
JMP GETEOL
|
||
USEDEF:
|
||
MOV SI,DI
|
||
LODSW ; Get default displacement
|
||
MOV DX,AX
|
||
LODSW ; Get default segment
|
||
RET
|
||
|
||
; Dump an area of memory in both hex and ASCII
|
||
|
||
DUMP:
|
||
MOV BP,[DSSAVE]
|
||
MOV CX,DISPB
|
||
MOV DI,OFFSET DG:DEFDUMP
|
||
CALL DEFAULT ; Get range if specified
|
||
MOV DS,AX ; Set segment
|
||
MOV SI,DX ; SI has displacement in segment
|
||
|
||
IF ZIBO
|
||
PUSH SI ; save SI away
|
||
AND SI,0FFF0h ; convert to para number
|
||
CALL OutSI ; display location
|
||
POP SI ; get SI back
|
||
MOV AX,SI ; move offset
|
||
MOV AH,3 ; spaces per byte
|
||
AND AL,0Fh ; convert to real offset
|
||
MUL AH ; compute (AL+1)*3-1
|
||
OR AL,AL ; set flag
|
||
JZ InRow ; if xero go on
|
||
PUSH CX ; save count
|
||
MOV CX,AX ; move to convenient spot
|
||
CALL Tab ; move over
|
||
POP CX ; get back count
|
||
JMP InRow ; display line
|
||
ENDIF
|
||
|
||
ROW:
|
||
CALL OUTSI ; Print address at start of line
|
||
InRow:
|
||
PUSH SI ; Save address for ASCII dump
|
||
CALL BLANK
|
||
BYTE0:
|
||
CALL BLANK ; Space between bytes
|
||
BYTE1:
|
||
LODSB ; Get byte to dump
|
||
CALL HEX ; and display it
|
||
POP DX ; DX has start addr. for ASCII dump
|
||
DEC CX ; Drop loop count
|
||
JZ ToAscii ; If through do ASCII dump
|
||
MOV AX,SI
|
||
TEST AL,CS:(BYTE PTR DSIZ) ; On 16-byte boundary?
|
||
JZ ENDROW
|
||
PUSH DX ; Didn't need ASCII addr. yet
|
||
TEST AL,7 ; On 8-byte boundary?
|
||
JNZ BYTE0
|
||
MOV AL,"-" ; Mark every 8 bytes
|
||
CALL OUT
|
||
JMP SHORT BYTE1
|
||
ENDROW:
|
||
CALL ASCII ; Show it in ASCII
|
||
JMP SHORT ROW ; Loop until count is zero
|
||
ToAscii:
|
||
MOV AX,SI ; get offset
|
||
AND AL,0Fh ; real offset
|
||
JZ ASCII ; no loop if already there
|
||
SUB AL,10h ; remainder
|
||
NEG AL
|
||
MOV CL,3
|
||
MUL CL
|
||
MOV CX,AX ; number of chars to move
|
||
CALL Tab
|
||
ASCII:
|
||
PUSH CX ; Save byte count
|
||
MOV AX,SI ; Current dump address
|
||
MOV SI,DX ; ASCII dump address
|
||
SUB AX,DX ; AX=length of ASCII dump
|
||
IF NOT ZIBO
|
||
; Compute tab length. ASCII dump always appears on right side
|
||
; screen regardless of how many bytes were dumped. Figure 3
|
||
; characters for each byte dumped and subtract from 51, which
|
||
; allows a minimum of 3 blanks after the last byte dumped.
|
||
MOV BX,AX
|
||
SHL AX,1 ; Length times 2
|
||
ADD AX,BX ; Length times 3
|
||
MOV CX,51
|
||
SUB CX,AX ; Amount to tab in CX
|
||
CALL TAB
|
||
MOV CX,BX ; ASCII dump length back in CX
|
||
ELSE
|
||
MOV CX,SI ; get starting point
|
||
DEC CX
|
||
AND CX,0Fh
|
||
INC CX
|
||
AND CX,0Fh
|
||
ADD CX,3 ; we have the correct number to tab
|
||
PUSH AX ; save count
|
||
CALL TAB
|
||
POP CX ; get count back
|
||
ENDIF
|
||
ASCDMP:
|
||
LODSB ; Get ASCII byte to dump
|
||
AND AL,7FH ; ASCII uses 7 bits
|
||
CMP AL,7FH ; Don't try to print RUBOUT
|
||
JZ NOPRT
|
||
CMP AL," " ; Check for control characters
|
||
JNC PRIN
|
||
NOPRT:
|
||
MOV AL,"." ; If unprintable character
|
||
PRIN:
|
||
CALL OUT ; Print ASCII character
|
||
LOOP ASCDMP ; CX times
|
||
POP CX ; Restore overall dump length
|
||
MOV ES:WORD PTR [DEFDUMP],SI
|
||
MOV ES:WORD PTR [DEFDUMP+2],DS ; Save last address as default
|
||
CALL CRLF ; Print CR/LF and return
|
||
RET
|
||
|
||
|
||
; Block move one area of memory to another. Overlapping moves
|
||
; are performed correctly, i.e., so that a source byte is not
|
||
; overwritten until after it has been moved.
|
||
|
||
MOVE:
|
||
CALL DSRANGE ; Get range of source area
|
||
PUSH CX ; Save length
|
||
PUSH AX ; Save segment
|
||
PUSH DX ; Save source displacement
|
||
CALL ADDRESS ; Get destination address (same segment)
|
||
CALL GETEOL ; Check for errors
|
||
POP SI
|
||
MOV DI,DX ; Set dest. displacement
|
||
POP BX ; Source segment
|
||
MOV DS,BX
|
||
MOV ES,AX ; Destination segment
|
||
POP CX ; Length
|
||
CMP DI,SI ; Check direction of move
|
||
SBB AX,BX ; Extend the CMP to 32 bits
|
||
JB COPYLIST ; Move forward into lower mem.
|
||
; Otherwise, move backward. Figure end of source and destination
|
||
; areas and flip direction flag.
|
||
DEC CX
|
||
ADD SI,CX ; End of source area
|
||
ADD DI,CX ; End of destination area
|
||
STD ; Reverse direction
|
||
INC CX
|
||
COPYLIST:
|
||
MOVSB ; Do at least 1 - Range is 1-10000H not 0-FFFFH
|
||
DEC CX
|
||
REP MOVSB ; Block move
|
||
RET1: RET
|
||
|
||
; Fill an area of memory with a list values. If the list
|
||
; is bigger than the area, don't use the whole list. If the
|
||
; list is smaller, repeat it as many times as necessary.
|
||
|
||
FILL:
|
||
CALL DSRANGE ; Get range to fill
|
||
PUSH CX ; Save length
|
||
PUSH AX ; Save segment number
|
||
PUSH DX ; Save displacement
|
||
CALL LIST ; Get list of values to fill with
|
||
POP DI ; Displacement in segment
|
||
POP ES ; Segment
|
||
POP CX ; Length
|
||
CMP BX,CX ; BX is length of fill list
|
||
MOV SI,OFFSET DG:BYTEBUF ; List is in byte buffer
|
||
JCXZ BIGRNG
|
||
JAE COPYLIST ; If list is big, copy part of it
|
||
BIGRNG:
|
||
SUB CX,BX ; How much bigger is area than list?
|
||
XCHG CX,BX ; CX=length of list
|
||
PUSH DI ; Save starting addr. of area
|
||
REP MOVSB ; Move list into area
|
||
POP SI
|
||
; The list has been copied into the beginning of the
|
||
; specified area of memory. SI is the first address
|
||
; of that area, DI is the end of the copy of the list
|
||
; plus one, which is where the list will begin to repeat.
|
||
; All we need to do now is copy [SI] to [DI] until the
|
||
; end of the memory area is reached. This will cause the
|
||
; list to repeat as many times as necessary.
|
||
MOV CX,BX ; Length of area minus list
|
||
PUSH ES ; Different index register
|
||
POP DS ; requires different segment reg.
|
||
JMP SHORT COPYLIST ; Do the block move
|
||
|
||
; Search a specified area of memory for given list of bytes.
|
||
; Print address of first byte of each match.
|
||
|
||
SEARCH:
|
||
CALL DSRANGE ; Get area to be searched
|
||
PUSH CX ; Save count
|
||
PUSH AX ; Save segment number
|
||
PUSH DX ; Save displacement
|
||
CALL LIST ; Get search list
|
||
DEC BX ; No. of bytes in list-1
|
||
POP DI ; Displacement within segment
|
||
POP ES ; Segment
|
||
POP CX ; Length to be searched
|
||
SUB CX,BX ; minus length of list
|
||
SCAN:
|
||
MOV SI,OFFSET DG:BYTEBUF ; List kept in byte buffer
|
||
LODSB ; Bring first byte into AL
|
||
DOSCAN:
|
||
SCASB ; Search for first byte
|
||
LOOPNE DOSCAN ; Do at least once by using LOOP
|
||
JNZ RET1 ; Exit if not found
|
||
PUSH BX ; Length of list minus 1
|
||
XCHG BX,CX
|
||
PUSH DI ; Will resume search here
|
||
REPE CMPSB ; Compare rest of string
|
||
MOV CX,BX ; Area length back in CX
|
||
POP DI ; Next search location
|
||
POP BX ; Restore list length
|
||
JNZ TEST ; Continue search if no match
|
||
DEC DI ; Match address
|
||
CALL OUTDI ; Print it
|
||
INC DI ; Restore search address
|
||
CALL CRLF
|
||
TEST:
|
||
JCXZ RET1
|
||
JMP SHORT SCAN ; Look for next occurrence
|
||
|
||
; Get the next parameter, which must be a hex number.
|
||
; CX is maximum number of digits the number may have.
|
||
|
||
GETHX:
|
||
CALL SCANP
|
||
GETHX1:
|
||
XOR DX,DX ; Initialize the number
|
||
CALL HEXIN ; Get a hex digit
|
||
JC HXERR ; Must be one valid digit
|
||
MOV DL,AL ; First 4 bits in position
|
||
GETLP:
|
||
INC SI ; Next char in buffer
|
||
DEC CX ; Digit count
|
||
CALL HEXIN ; Get another hex digit?
|
||
JC RETHX ; All done if no more digits
|
||
STC
|
||
JCXZ HXERR ; Too many digits?
|
||
SHL DX,1 ; Multiply by 16
|
||
SHL DX,1
|
||
SHL DX,1
|
||
SHL DX,1
|
||
OR DL,AL ; and combine new digit
|
||
JMP SHORT GETLP ; Get more digits
|
||
|
||
GETHEX:
|
||
CALL GETHX ; Scan to next parameter
|
||
JMP SHORT GETHX2
|
||
GETHEX1:
|
||
CALL GETHX1
|
||
GETHX2: JC PERROR
|
||
RETHX: CLC
|
||
HXERR: RET
|
||
|
||
|
||
; Check if next character in the input buffer is a hex digit
|
||
; and convert it to binary if it is. Carry set if not.
|
||
|
||
HEXIN:
|
||
MOV AL,[SI]
|
||
|
||
; Check if AL has a hex digit and convert it to binary if it
|
||
; is. Carry set if not.
|
||
|
||
HEXCHK:
|
||
SUB AL,"0" ; Kill ASCII numeric bias
|
||
JC RET2
|
||
CMP AL,10
|
||
CMC
|
||
JNC RET2 ; OK if 0-9
|
||
AND AL,5FH
|
||
SUB AL,7 ; Kill A-F bias
|
||
CMP AL,10
|
||
JC RET2
|
||
CMP AL,16
|
||
CMC
|
||
RET2: RET
|
||
|
||
; Process one parameter when a list of bytes is
|
||
; required. Carry set if parameter bad. Called by LIST.
|
||
|
||
LISTITEM:
|
||
CALL SCANP ; Scan to parameter
|
||
CALL HEXIN ; Is it in hex?
|
||
JC STRINGCHK ; If not, could be a string
|
||
MOV CX,2 ; Only 2 hex digits for bytes
|
||
CALL GETHEX ; Get the byte value
|
||
MOV [BX],DL ; Add to list
|
||
INC BX
|
||
GRET: CLC ; Parameter was OK
|
||
RET
|
||
STRINGCHK:
|
||
MOV AL,[SI] ; Get first character of param
|
||
CMP AL,"'" ; String?
|
||
JZ STRING
|
||
CMP AL,'"' ; Either quote is all right
|
||
JZ STRING
|
||
STC ; Not string, not hex - bad
|
||
RET
|
||
STRING:
|
||
MOV AH,AL ; Save for closing quote
|
||
INC SI
|
||
STRNGLP:
|
||
LODSB ; Next char of string
|
||
CMP AL,13 ; Check for end of line
|
||
JZ PERR ; Must find a close quote
|
||
CMP AL,AH ; Check for close quote
|
||
JNZ STOSTRG ; Add new character to list
|
||
CMP AH,[SI] ; Two quotes in a row?
|
||
JNZ GRET ; If not, we're done
|
||
INC SI ; Yes - skip second one
|
||
STOSTRG:
|
||
MOV [BX],AL ; Put new char in list
|
||
INC BX
|
||
JMP SHORT STRNGLP ; Get more characters
|
||
|
||
; Get a byte list for ENTER, FILL or SEARCH. Accepts any number
|
||
; of 2-digit hex values or character strings in either single
|
||
; (') or double (") quotes.
|
||
|
||
LIST:
|
||
MOV BX,OFFSET DG:BYTEBUF ; Put byte list in the byte buffer
|
||
LISTLP:
|
||
CALL LISTITEM ; Process a parameter
|
||
JNC LISTLP ; If OK, try for more
|
||
SUB BX,OFFSET DG:BYTEBUF ; BX now has no. of bytes in list
|
||
JZ PERROR ; List must not be empty
|
||
|
||
; Make sure there is nothing more on the line except for
|
||
; blanks and carriage return. If there is, it is an
|
||
; unrecognized parameter and an error.
|
||
|
||
GETEOL:
|
||
CALL SCANB ; Skip blanks
|
||
JNZ PERROR ; Better be a RETURN
|
||
RET3: RET
|
||
|
||
; Command error. SI has been incremented beyond the
|
||
; command letter so it must decremented for the
|
||
; error pointer to work.
|
||
|
||
PERR:
|
||
DEC SI
|
||
|
||
; Syntax error. SI points to character in the input buffer
|
||
; which caused error. By subtracting from start of buffer,
|
||
; we will know how far to tab over to appear directly below
|
||
; it on the terminal. Then print "^ Error".
|
||
|
||
PERROR:
|
||
SUB SI,OFFSET DG:(BYTEBUF-1); How many char processed so far?
|
||
MOV CX,SI ; Parameter for TAB in CX
|
||
CALL TAB ; Directly below bad char
|
||
MOV SI,OFFSET DG:SYNERR ; Error message
|
||
|
||
; Print error message and abort to command level
|
||
|
||
PRINT:
|
||
CALL PRINTMES
|
||
JMP COMMAND
|
||
|
||
; Gets an address in Segment:Displacement format. Segment may be omitted
|
||
; and a default (kept in BP) will be used, or it may be a segment
|
||
; register (DS, ES, SS, CS). Returns with segment in AX, OFFSET in DX.
|
||
|
||
ADDRESS:
|
||
CALL GET_ADDRESS
|
||
JC PERROR
|
||
ADRERR: STC
|
||
RET
|
||
|
||
GET_ADDRESS:
|
||
CALL SCANP
|
||
MOV AL,[SI+1]
|
||
CMP AL,"S"
|
||
JZ SEGREG
|
||
MOV CX,4
|
||
CALL GETHX
|
||
JC ADRERR
|
||
MOV AX,BP ; Get default segment
|
||
CMP BYTE PTR [SI],":"
|
||
JNZ GETRET
|
||
PUSH DX
|
||
GETDISP:
|
||
INC SI ; Skip over ":"
|
||
MOV CX,4
|
||
CALL GETHX
|
||
POP AX
|
||
JC ADRERR
|
||
GETRET: CLC
|
||
RET
|
||
SEGREG:
|
||
MOV AL,[SI]
|
||
MOV DI,OFFSET DG:SEGLET
|
||
MOV CX,4
|
||
REPNE SCASB
|
||
JNZ ADRERR
|
||
INC SI
|
||
INC SI
|
||
SHL CX,1
|
||
MOV BX,CX
|
||
CMP BYTE PTR [SI],":"
|
||
JNZ ADRERR
|
||
PUSH [BX+DSSAVE]
|
||
JMP SHORT GETDISP
|
||
|
||
SEGLET DB "CSED"
|
||
|
||
; Short form of ENTER command. A list of values from the
|
||
; command line are put into memory without using normal
|
||
; ENTER mode.
|
||
|
||
GETLIST:
|
||
CALL LIST ; Get the bytes to enter
|
||
POP DI ; Displacement within segment
|
||
POP ES ; Segment to enter into
|
||
MOV SI,OFFSET DG:BYTEBUF ; List of bytes is in byte 2uffer
|
||
MOV CX,BX ; Count of bytes
|
||
REP MOVSB ; Enter that byte list
|
||
RET
|
||
|
||
; Enter values into memory at a specified address. If the
|
||
; line contains nothing but the address we go into "enter
|
||
; mode", where the address and its current value are printed
|
||
; and the user may change it if desired. To change, type in
|
||
; new value in hex. Backspace works to correct errors. If
|
||
; an illegal hex digit or too many digits are typed, the
|
||
; bell is sounded but it is otherwise ignored. To go to the
|
||
; next byte (with or without change), hit space bar. To
|
||
; back CLDto a previous address, type "-". On
|
||
; every 8-byte boundary a new line is started and the address
|
||
; is printed. To terminate command, type carriage return.
|
||
; Alternatively, the list of bytes to be entered may be
|
||
; included on the original command line immediately following
|
||
; the address. This is in regular LIST format so any number
|
||
; of hex values or strings in quotes may be entered.
|
||
|
||
ENTER:
|
||
MOV BP,[DSSAVE] ; Set default segment to DS
|
||
CALL ADDRESS
|
||
PUSH AX ; Save for later
|
||
PUSH DX
|
||
CALL SCANB ; Any more parameters?
|
||
JNZ GETLIST ; If not end-of-line get list
|
||
POP DI ; Displacement of ENTER
|
||
POP ES ; Segment
|
||
GETROW:
|
||
CALL OUTDI ; Print address of entry
|
||
CALL BLANK ; Leave a space
|
||
CALL BLANK
|
||
GETBYTE:
|
||
MOV AL,ES:[DI] ; Get current value
|
||
CALL HEX ; And display it
|
||
PUTDOT:
|
||
MOV AL,"."
|
||
CALL OUT ; Prompt for new value
|
||
MOV CX,2 ; Max of 2 digits in new value
|
||
MOV DX,0 ; Intial new value
|
||
GETDIG:
|
||
CALL IN ; Get digit from user
|
||
MOV AH,AL ; Save
|
||
CALL HEXCHK ; Hex digit?
|
||
XCHG AH,AL ; Need original for echo
|
||
JC NOHEX ; If not, try special command
|
||
MOV DH,DL ; Rotate new value
|
||
MOV DL,AH ; And include new digit
|
||
LOOP GETDIG ; At most 2 digits
|
||
; We have two digits, so all we will accept now is a command.
|
||
DWAIT:
|
||
CALL IN ; Get command character
|
||
NOHEX:
|
||
CMP AL,8 ; Backspace
|
||
JZ BS
|
||
CMP AL,7FH ; RUBOUT
|
||
JZ RUB
|
||
CMP AL,"-" ; Back CLDto previous address
|
||
JZ PREV
|
||
CMP AL,13 ; All done with command?
|
||
JZ EOL
|
||
CMP AL," " ; Go to next address
|
||
JZ NEXT
|
||
MOV AL,8
|
||
CALL OUT ; Back CLDover illegal character
|
||
CALL BACKUP
|
||
JCXZ DWAIT
|
||
JMP SHORT GETDIG
|
||
|
||
RUB:
|
||
MOV AL,8
|
||
CALL OUT
|
||
BS:
|
||
CMP CL,2 ; CX=2 means nothing typed yet
|
||
JZ PUTDOT ; Put back the dot we backed CLDover
|
||
INC CL ; Accept one more character
|
||
MOV DL,DH ; Rotate out last digit
|
||
MOV DH,CH ; Zero this digit
|
||
CALL BACKUP ; Physical backspace
|
||
JMP SHORT GETDIG ; Get more digits
|
||
|
||
; If new value has been entered, convert it to binary and
|
||
; put into memory. Always bump pointer to next location
|
||
|
||
STORE:
|
||
CMP CL,2 ; CX=2 means nothing typed yet
|
||
JZ NOSTO ; So no new value to store
|
||
; Rotate DH left 4 bits to combine with DL and make a byte value
|
||
PUSH CX
|
||
MOV CL,4
|
||
SHL DH,CL
|
||
POP CX
|
||
OR DL,DH ; Hex is now converted to binary
|
||
MOV ES:[DI],DL ; Store new value
|
||
NOSTO:
|
||
INC DI ; Prepare for next location
|
||
RET
|
||
NEXT:
|
||
CALL STORE ; Enter new value
|
||
INC CX ; Leave a space plus two for
|
||
INC CX ; each digit not entered
|
||
CALL TAB
|
||
MOV AX,DI ; Next memory address
|
||
AND AL,7 ; Check for 8-byte boundary
|
||
JNZ GETBYTE ; Take 8 per line
|
||
NEWROW:
|
||
CALL CRLF ; Terminate line
|
||
JMP GETROW ; Print address on new line
|
||
PREV:
|
||
CALL STORE ; Enter the new value
|
||
; DI has been bumped to next byte. Drop it 2 to go to previous addr
|
||
DEC DI
|
||
DEC DI
|
||
JMP SHORT NEWROW ; Terminate line after backing CLD
|
||
|
||
EOL:
|
||
CALL STORE ; Enter the new value
|
||
JMP CRLF ; CR/LF and terminate
|
||
|
||
; Console input of single character
|
||
|
||
IF SYSVER
|
||
IN:
|
||
PUSH DS
|
||
PUSH SI
|
||
LDS SI,CS:[CIN]
|
||
MOV AH,4
|
||
CALL DEVIOCALL
|
||
POP SI
|
||
POP DS
|
||
CMP AL,3
|
||
JNZ NOTCNTC
|
||
INT 23H
|
||
NOTCNTC:
|
||
CMP AL,'P'-'@'
|
||
JZ PRINTON
|
||
CMP AL,'N'-'@'
|
||
JZ PRINTOFF
|
||
CALL OUT
|
||
RET
|
||
|
||
PRINTOFF:
|
||
PRINTON:
|
||
NOT [PFLAG]
|
||
JMP SHORT IN
|
||
|
||
ELSE
|
||
|
||
IN:
|
||
MOV AH,1
|
||
INT 21H
|
||
RET
|
||
ENDIF
|
||
|
||
CODE ENDS
|
||
END DEBCOM1
|
||
|