mirror of https://github.com/microsoft/MS-DOS.git
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
|
|||
|
|