MS-DOS/v2.0/source/DEBCOM1.ASM
2018-09-21 17:53:34 -07:00

694 lines
26 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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