1270 lines
35 KiB
NASM
1270 lines
35 KiB
NASM
TITLE PART2 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 NOTFND:BYTE,NOROOM:BYTE,DRVLET:BYTE,NOSPACE:BYTE,NAMBAD:BYTE
|
|
EXTRN TOOBIG:BYTE,ERRMES:BYTE
|
|
EXTRN EXEBAD:BYTE,HEXERR:BYTE,EXEWRT:BYTE,HEXWRT:BYTE
|
|
EXTRN EXECEMES:BYTE,WRTMES1:BYTE,WRTMES2:BYTE,ACCMES:BYTE
|
|
|
|
EXTRN FLAGTAB:WORD,EXEC_BLOCK:BYTE,COM_LINE:DWORD,COM_FCB1:DWORD
|
|
EXTRN COM_FCB2:DWORD,COM_SSSP:DWORD,COM_CSIP:DWORD,RETSAVE:WORD
|
|
EXTRN NEWEXEC:BYTE,HEADSAVE:WORD
|
|
EXTRN REGTAB:BYTE,TOTREG:BYTE,NOREGL:BYTE
|
|
EXTRN USER_PROC_PDB:WORD,STACK:BYTE,RSTACK:WORD,AXSAVE:WORD
|
|
EXTRN BXSAVE:WORD,DSSAVE:WORD,ESSAVE:WORD,CSSAVE:WORD,IPSAVE:WORD
|
|
EXTRN SSSAVE:WORD,CXSAVE:WORD,SPSAVE:WORD,FSAVE:WORD
|
|
EXTRN SREG:BYTE,SEGTAB:WORD,REGDIF:WORD,RDFLG:BYTE
|
|
|
|
CONST ENDS
|
|
|
|
DATA SEGMENT PUBLIC BYTE
|
|
|
|
EXTRN DEFDUMP:BYTE,TRANSADD:DWORD,INDEX:WORD,BUFFER:BYTE
|
|
EXTRN ASMADD:BYTE,DISADD:BYTE,NSEG:WORD,BPTAB:BYTE
|
|
EXTRN BRKCNT:WORD,TCOUNT:WORD,SWITCHAR:BYTE,XNXCMD:BYTE,XNXOPT:BYTE
|
|
EXTRN AWORD:BYTE,EXTPTR:WORD,HANDLE:WORD,PARSERR:BYTE
|
|
|
|
DATA ENDS
|
|
|
|
DG GROUP CODE,CONST,DATA
|
|
|
|
|
|
CODE SEGMENT PUBLIC BYTE 'CODE'
|
|
ASSUME CS:DG,DS:DG,ES:DG,SS:DG
|
|
|
|
PUBLIC DEFIO,SKIP_FILE,PREPNAME,DEBUG_FOUND
|
|
PUBLIC REG,COMPARE,GO,INPUT,LOAD
|
|
PUBLIC NAME,OUTPUT,TRACE,ZTRACE,DWRITE
|
|
if sysver
|
|
PUBLIC DISPREG
|
|
endif
|
|
|
|
EXTRN GETHEX:NEAR,GETEOL:NEAR
|
|
EXTRN CRLF:NEAR,BLANK:NEAR,OUT:NEAR
|
|
EXTRN OUTSI:NEAR,OUTDI:NEAR,INBUF:NEAR,SCANB:NEAR,SCANP:NEAR
|
|
EXTRN RPRBUF:NEAR,HEX:NEAR,OUT16:NEAR,DIGIT:NEAR
|
|
EXTRN COMMAND:NEAR,DISASLN:NEAR,SET_TERMINATE_VECTOR:NEAR
|
|
EXTRN RESTART:NEAR,DABORT:NEAR,TERMINATE:NEAR,DRVERR:NEAR
|
|
EXTRN FIND_DEBUG:NEAR,NMIInt:NEAR,NMIIntEnd:NEAR
|
|
EXTRN HEXCHK:NEAR,GETHEX1:NEAR,PRINT:NEAR,DSRANGE:NEAR
|
|
EXTRN ADDRESS:NEAR,HEXIN:NEAR,PERROR:NEAR
|
|
|
|
|
|
DEBCOM2:
|
|
DISPREG:
|
|
MOV SI,OFFSET DG:REGTAB
|
|
MOV BX,OFFSET DG:AXSAVE
|
|
MOV BYTE PTR TOTREG,13
|
|
MOV CH,0
|
|
MOV CL,NOREGL
|
|
REPDISP:
|
|
SUB TOTREG,CL
|
|
CALL DISPREGLINE
|
|
CALL CRLF
|
|
MOV CH,0
|
|
MOV CL,NOREGL
|
|
CMP CL,TOTREG
|
|
JL REPDISP
|
|
MOV CL,TOTREG
|
|
CALL DISPREGLINE
|
|
CALL BLANK
|
|
CALL DISPFLAGS
|
|
CALL CRLF
|
|
MOV AX,[IPSAVE]
|
|
MOV WORD PTR [DISADD],AX
|
|
PUSH AX
|
|
MOV AX,[CSSAVE]
|
|
MOV WORD PTR [DISADD+2],AX
|
|
PUSH AX
|
|
MOV [NSEG],-1
|
|
CALL DISASLN
|
|
POP WORD PTR DISADD+2
|
|
POP WORD PTR DISADD
|
|
MOV AX,[NSEG]
|
|
CMP AL,-1
|
|
JZ CRLFJ
|
|
CMP AH,-1
|
|
JZ NOOVER
|
|
XCHG AL,AH
|
|
NOOVER:
|
|
CBW
|
|
MOV BX,AX
|
|
SHL BX,1
|
|
MOV AX,WORD PTR [BX+SREG]
|
|
CALL OUT
|
|
XCHG AL,AH
|
|
CALL OUT
|
|
MOV AL,":"
|
|
CALL OUT
|
|
MOV DX,[INDEX]
|
|
CALL OUT16
|
|
MOV AL,"="
|
|
CALL OUT
|
|
MOV BX,[BX+SEGTAB]
|
|
PUSH DS
|
|
MOV DS,[BX]
|
|
MOV BX,DX
|
|
MOV DX,[BX]
|
|
POP DS
|
|
TEST BYTE PTR [AWORD],-1
|
|
JZ OUT8
|
|
CALL OUT16
|
|
CRLFJ:
|
|
JMP CRLF
|
|
OUT8:
|
|
MOV AL,DL
|
|
CALL HEX
|
|
JMP CRLF
|
|
|
|
DISPREGJ:JMP DISPREG
|
|
|
|
; Perform register dump if no parameters or set register if a
|
|
; register designation is a parameter.
|
|
|
|
REG:
|
|
CALL SCANP
|
|
JZ DISPREGJ
|
|
MOV DL,[SI]
|
|
INC SI
|
|
MOV DH,[SI]
|
|
CMP DH,13
|
|
JZ FLAG
|
|
INC SI
|
|
CALL GETEOL
|
|
CMP DH," "
|
|
JZ FLAG
|
|
MOV DI,OFFSET DG:REGTAB
|
|
XCHG AX,DX
|
|
PUSH CS
|
|
POP ES
|
|
MOV CX,REGTABLEN
|
|
REPNZ SCASW
|
|
JNZ BADREG
|
|
OR CX,CX
|
|
JNZ NOTPC
|
|
DEC DI
|
|
DEC DI
|
|
MOV AX,CS:[DI-2]
|
|
NOTPC:
|
|
CALL OUT
|
|
MOV AL,AH
|
|
CALL OUT
|
|
CALL BLANK
|
|
PUSH DS
|
|
POP ES
|
|
LEA BX,[DI+REGDIF-2]
|
|
MOV DX,[BX]
|
|
CALL OUT16
|
|
CALL CRLF
|
|
MOV AL,":"
|
|
CALL OUT
|
|
CALL INBUF
|
|
CALL SCANB
|
|
JZ RET4
|
|
MOV CX,4
|
|
CALL GETHEX1
|
|
CALL GETEOL
|
|
MOV [BX],DX
|
|
RET4: RET
|
|
BADREG:
|
|
MOV AX,5200H+"B" ; BR ERROR
|
|
JMP ERR
|
|
FLAG:
|
|
CMP DL,"F"
|
|
JNZ BADREG
|
|
CALL DISPFLAGS
|
|
MOV AL,"-"
|
|
CALL OUT
|
|
CALL INBUF
|
|
CALL SCANB
|
|
XOR BX,BX
|
|
MOV DX,[FSAVE]
|
|
GETFLG:
|
|
LODSW
|
|
CMP AL,13
|
|
JZ SAVCHG
|
|
CMP AH,13
|
|
JZ FLGERR
|
|
MOV DI,OFFSET DG:FLAGTAB
|
|
MOV CX,32
|
|
PUSH CS
|
|
POP ES
|
|
REPNE SCASW
|
|
JNZ FLGERR
|
|
MOV CH,CL
|
|
AND CL,0FH
|
|
MOV AX,1
|
|
ROL AX,CL
|
|
TEST AX,BX
|
|
JNZ REPFLG
|
|
OR BX,AX
|
|
OR DX,AX
|
|
TEST CH,16
|
|
JNZ NEXFLG
|
|
XOR DX,AX
|
|
NEXFLG:
|
|
CALL SCANP
|
|
JMP SHORT GETFLG
|
|
DISPREGLINE:
|
|
LODS CS:WORD PTR [SI]
|
|
CALL OUT
|
|
MOV AL,AH
|
|
CALL OUT
|
|
MOV AL,"="
|
|
CALL OUT
|
|
MOV DX,[BX]
|
|
INC BX
|
|
INC BX
|
|
CALL OUT16
|
|
CALL BLANK
|
|
CALL BLANK
|
|
LOOP DISPREGLINE
|
|
RET
|
|
REPFLG:
|
|
MOV AX,4600H+"D" ; DF ERROR
|
|
FERR:
|
|
CALL SAVCHG
|
|
ERR:
|
|
CALL OUT
|
|
MOV AL,AH
|
|
CALL OUT
|
|
MOV SI,OFFSET DG:ERRMES
|
|
JMP PRINT
|
|
SAVCHG:
|
|
MOV [FSAVE],DX
|
|
RET
|
|
FLGERR:
|
|
MOV AX,4600H+"B" ; BF ERROR
|
|
JMP SHORT FERR
|
|
DISPFLAGS:
|
|
MOV SI,OFFSET DG:FLAGTAB
|
|
MOV CX,16
|
|
MOV DX,[FSAVE]
|
|
DFLAGS:
|
|
LODS CS:WORD PTR [SI]
|
|
SHL DX,1
|
|
JC FLAGSET
|
|
MOV AX,CS:[SI+30]
|
|
FLAGSET:
|
|
OR AX,AX
|
|
JZ NEXTFLG
|
|
CALL OUT
|
|
MOV AL,AH
|
|
CALL OUT
|
|
CALL BLANK
|
|
NEXTFLG:
|
|
LOOP DFLAGS
|
|
RET
|
|
|
|
; Input from the specified port and display result
|
|
|
|
INPUT:
|
|
MOV CX,4 ; Port may have 4 digits
|
|
CALL GETHEX ; Get port number in DX
|
|
CALL GETEOL
|
|
IN AL,DX ; Variable port input
|
|
CALL HEX ; And display
|
|
JMP CRLF
|
|
|
|
; Output a value to specified port.
|
|
|
|
OUTPUT:
|
|
MOV CX,4 ; Port may have 4 digits
|
|
CALL GETHEX ; Get port number
|
|
PUSH DX ; Save while we get data
|
|
MOV CX,2 ; Byte output only
|
|
CALL GETHEX ; Get data to output
|
|
CALL GETEOL
|
|
XCHG AX,DX ; Output data in AL
|
|
POP DX ; Port in DX
|
|
OUT DX,AL ; Variable port output
|
|
RET5: RET
|
|
COMPARE:
|
|
CALL DSRANGE
|
|
PUSH CX
|
|
PUSH AX
|
|
PUSH DX
|
|
CALL ADDRESS ; Same segment
|
|
CALL GETEOL
|
|
POP SI
|
|
MOV DI,DX
|
|
MOV ES,AX
|
|
POP DS
|
|
POP CX ; Length
|
|
DEC CX
|
|
CALL COMP ; Do one less than total
|
|
INC CX ; CX=1 (do last one)
|
|
COMP:
|
|
REPE CMPSB
|
|
JZ RET5
|
|
; Compare error. Print address, value; value, address.
|
|
DEC SI
|
|
CALL OUTSI
|
|
CALL BLANK
|
|
CALL BLANK
|
|
LODSB
|
|
CALL HEX
|
|
CALL BLANK
|
|
CALL BLANK
|
|
DEC DI
|
|
MOV AL,ES:[DI]
|
|
CALL HEX
|
|
CALL BLANK
|
|
CALL BLANK
|
|
CALL OUTDI
|
|
INC DI
|
|
CALL CRLF
|
|
XOR AL,AL
|
|
JMP SHORT COMP
|
|
|
|
ZTRACE:
|
|
IF ZIBO
|
|
; just like trace except skips OVER next INT or CALL.
|
|
CALL SETADD ; get potential starting point
|
|
CALL GETEOL ; check for end of line
|
|
MOV [TCOUNT],1 ; only a single go at it
|
|
MOV ES,[CSSAVE] ; point to instruction to execute
|
|
MOV DI,[IPSAVE] ; include offset in segment
|
|
XOR DX,DX ; where to place breakpoint
|
|
MOV AL,ES:[DI] ; get the opcode
|
|
CMP AL,11101000B ; direct intra call
|
|
JZ ZTrace3 ; yes, 3 bytes
|
|
CMP AL,10011010B ; direct inter call
|
|
JZ ZTrace5 ; yes, 5 bytes
|
|
CMP AL,11111111B ; indirect?
|
|
JZ ZTraceModRM ; yes, go figure length
|
|
CMP AL,11001100B ; short interrupt?
|
|
JZ ZTrace1 ; yes, 1 byte
|
|
CMP AL,11001101B ; long interrupt?
|
|
JZ ZTrace2 ; yes, 2 bytes
|
|
CMP AL,11100010B ; loop
|
|
JZ ZTrace2 ; 2 byter
|
|
CMP AL,11100001B ; loopz/loope
|
|
JZ ZTrace2 ; 2 byter
|
|
CMP AL,11100000B ; loopnz/loopne
|
|
JZ ZTrace2 ; 2 byter
|
|
AND AL,11111110B ; check for rep
|
|
CMP AL,11110010B ; perhaps?
|
|
JNZ Step ; can't do anything special, step
|
|
MOV AL,ES:[DI+1] ; next instruction
|
|
AND AL,11111110B ; ignore w bit
|
|
CMP AL,10100100B ; MOVS
|
|
JZ ZTrace2 ; two byte
|
|
CMP AL,10100110B ; CMPS
|
|
JZ ZTrace2 ; two byte
|
|
CMP AL,10101110B ; SCAS
|
|
JZ ZTrace2 ; two byte
|
|
CMP AL,10101100B ; LODS
|
|
JZ ZTrace2 ; two byte
|
|
CMP AL,10101010B ; STOS
|
|
JZ ZTrace2 ; two byte
|
|
JMP Step ; bogus, do single step
|
|
|
|
ZTraceModRM:
|
|
MOV AL,ES:[DI+1] ; get next byte
|
|
AND AL,11111000B ; get mod and type
|
|
CMP AL,01010000B ; indirect intra 8 bit offset?
|
|
JZ ZTrace3 ; yes, three byte whammy
|
|
CMP AL,01011000B ; indirect inter 8 bit offset
|
|
JZ ZTrace3 ; yes, three byte guy
|
|
CMP AL,10010000B ; indirect intra 16 bit offset?
|
|
JZ ZTrace4 ; four byte offset
|
|
CMP AL,10011000B ; indirect inter 16 bit offset?
|
|
JZ ZTrace4 ; four bytes
|
|
JMP Step ; can't figger out what this is!
|
|
ZTrace5:INC DX
|
|
ZTrace4:INC DX
|
|
ZTrace3:INC DX
|
|
ZTrace2:INC DX
|
|
ZTrace1:INC DX
|
|
ADD DI,DX ; offset to breakpoint instruction
|
|
MOV WORD PTR [BPTab],DI ; save offset
|
|
MOV WORD PTR [BPTab+2],ES ; save segment
|
|
MOV AL,ES:[DI] ; get next opcode byte
|
|
MOV BYTE PTR [BPTab+4],AL ; save it
|
|
MOV BYTE PTR ES:[DI],0CCh ; break point it
|
|
MOV [BrkCnt],1 ; only this breakpoint
|
|
JMP DExit ; start the operation!
|
|
ENDIF
|
|
|
|
; Trace 1 instruction or the number of instruction specified
|
|
; by the parameter using 8086 trace mode. Registers are all
|
|
; set according to values in save area
|
|
|
|
TRACE:
|
|
CALL SETADD
|
|
CALL SCANP
|
|
CALL HEXIN
|
|
MOV DX,1
|
|
JC STOCNT
|
|
MOV CX,4
|
|
CALL GETHEX
|
|
STOCNT:
|
|
MOV [TCOUNT],DX
|
|
CALL GETEOL
|
|
STEP:
|
|
MOV [BRKCNT],0
|
|
OR BYTE PTR [FSAVE+1],1
|
|
DEXIT:
|
|
IF NOT SYSVER
|
|
MOV BX,[USER_PROC_PDB]
|
|
MOV AH,SET_CURRENT_PDB
|
|
INT 21H
|
|
ENDIF
|
|
PUSH DS
|
|
XOR AX,AX
|
|
MOV DS,AX
|
|
MOV WORD PTR DS:[12],OFFSET DG:BREAKFIX ; Set vector 3--breakpoint instruction
|
|
MOV WORD PTR DS:[14],CS
|
|
MOV WORD PTR DS:[4],OFFSET DG:REENTER ; Set vector 1--Single step
|
|
MOV WORD PTR DS:[6],CS
|
|
CLI
|
|
|
|
IF SETCNTC
|
|
MOV WORD PTR DS:[8CH],OFFSET DG:CONTC ; Set vector 23H (CTRL-C)
|
|
MOV WORD PTR DS:[8EH],CS
|
|
ENDIF
|
|
|
|
POP DS
|
|
MOV SP,OFFSET DG:STACK
|
|
POP AX
|
|
POP BX
|
|
POP CX
|
|
POP DX
|
|
POP BP
|
|
POP BP
|
|
POP SI
|
|
POP DI
|
|
POP ES
|
|
POP ES
|
|
POP SS
|
|
MOV SP,[SPSAVE]
|
|
PUSH [FSAVE]
|
|
PUSH [CSSAVE]
|
|
PUSH [IPSAVE]
|
|
MOV DS,[DSSAVE]
|
|
IRET
|
|
STEP1:
|
|
CALL CRLF
|
|
CALL DISPREG
|
|
JMP SHORT STEP
|
|
|
|
; Re-entry point from CTRL-C. Top of stack has address in 86-DOS for
|
|
; continuing, so we must pop that off.
|
|
|
|
CONTC:
|
|
ADD SP,6
|
|
JMP SHORT ReEnterReal
|
|
|
|
; Re-entry point from breakpoint. Need to decrement instruction
|
|
; pointer so it points to location where breakpoint actually
|
|
; occured.
|
|
|
|
BREAKFIX:
|
|
PUSH BP
|
|
MOV BP,SP
|
|
DEC WORD PTR [BP].OldIP
|
|
POP BP
|
|
JMP ReenterReal
|
|
|
|
; Re-entry point from trace mode or interrupt during
|
|
; execution. All registers are saved so they can be
|
|
; displayed or modified.
|
|
|
|
Interrupt_Frame STRUC
|
|
OldBP DW ?
|
|
OldIP DW ?
|
|
OldCS DW ?
|
|
OldF DW ?
|
|
OlderIP DW ?
|
|
OlderCS DW ?
|
|
OlderF DW ?
|
|
Interrupt_Frame ENDS
|
|
|
|
REENTER:
|
|
PUSH BP
|
|
MOV BP,SP ; get a frame to address from
|
|
PUSH AX
|
|
MOV AX,CS
|
|
CMP AX,[BP].OldCS ; Did we interrupt ourselves?
|
|
JNZ GoReEnter ; no, go reenter
|
|
MOV AX,[BP].OldIP
|
|
CMP AX,OFFSET DG:NMIInt ; interrupt below NMI interrupt?
|
|
JB GoReEnter ; yes, go reenter
|
|
CMP [BP].OLDIP,OFFSET DG:NMIIntEnd
|
|
JAE GoReEnter ; interrupt above NMI interrupt?
|
|
POP AX ; restore state
|
|
POP BP
|
|
SUB SP,6 ; switch TRACE and NMI stack frames
|
|
PUSH BP
|
|
MOV BP,SP ; set up frame
|
|
PUSH AX ; get temp variable
|
|
MOV AX,[BP].OlderIP ; get NMI Vector
|
|
MOV [BP].OldIP,AX ; stuff in new NMI vector
|
|
MOV AX,[BP].OlderCS ; get NMI Vector
|
|
MOV [BP].OldCS,AX ; stuff in new NMI vector
|
|
MOV AX,[BP].OlderF ; get NMI Vector
|
|
AND AH,0FEh ; turn off Trace if present
|
|
MOV [BP].OldF,AX ; stuff in new NMI vector
|
|
MOV [BP].OlderF,AX
|
|
MOV [BP].OlderIP,OFFSET DG:ReEnter ; offset of routine
|
|
MOV [BP].OlderCS,CS ; and CS
|
|
POP AX
|
|
POP BP
|
|
IRET ; go try again
|
|
GoReEnter:
|
|
POP AX
|
|
POP BP
|
|
ReEnterReal:
|
|
MOV CS:[SPSAVE+SEGDIF],SP
|
|
MOV CS:[SSSAVE+SEGDIF],SS
|
|
MOV CS:[FSAVE],CS
|
|
MOV SS,CS:[FSAVE]
|
|
MOV SP,OFFSET DG:RSTACK
|
|
PUSH ES
|
|
PUSH DS
|
|
PUSH DI
|
|
PUSH SI
|
|
PUSH BP
|
|
DEC SP
|
|
DEC SP
|
|
PUSH DX
|
|
PUSH CX
|
|
PUSH BX
|
|
PUSH AX
|
|
PUSH SS
|
|
POP DS
|
|
MOV SS,[SSSAVE]
|
|
MOV SP,[SPSAVE]
|
|
POP [IPSAVE]
|
|
POP [CSSAVE]
|
|
POP AX
|
|
AND AH,0FEH ; turn off trace mode bit
|
|
MOV [FSAVE],AX
|
|
MOV [SPSAVE],SP
|
|
PUSH DS
|
|
POP ES
|
|
PUSH DS
|
|
POP SS
|
|
MOV SP,OFFSET DG:STACK
|
|
PUSH DS
|
|
XOR AX,AX
|
|
MOV DS,AX
|
|
|
|
IF SETCNTC
|
|
MOV WORD PTR DS:[8CH],OFFSET DG:DABORT ; Set Ctrl-C vector
|
|
MOV WORD PTR DS:[8EH],CS
|
|
ENDIF
|
|
|
|
POP DS
|
|
STI
|
|
CLD
|
|
IF NOT SYSVER
|
|
MOV AH,GET_CURRENT_PDB
|
|
INT 21H
|
|
MOV [USER_PROC_PDB],BX
|
|
MOV BX,DS
|
|
MOV AH,SET_CURRENT_PDB
|
|
INT 21H
|
|
ENDIF
|
|
DEC [TCOUNT]
|
|
JZ CheckDisp
|
|
JMP Step1
|
|
CheckDisp:
|
|
MOV SI,OFFSET DG:BPTAB
|
|
MOV CX,[BRKCNT]
|
|
JCXZ SHOREG
|
|
PUSH ES
|
|
CLEARBP:
|
|
LES DI,DWORD PTR [SI]
|
|
ADD SI,4
|
|
MOVSB
|
|
LOOP CLEARBP
|
|
POP ES
|
|
SHOREG:
|
|
CALL CRLF
|
|
CALL DISPREG
|
|
JMP COMMAND
|
|
|
|
SETADD:
|
|
MOV BP,[CSSAVE]
|
|
CALL SCANP
|
|
CMP BYTE PTR [SI],"="
|
|
JNZ RET$5
|
|
INC SI
|
|
CALL ADDRESS
|
|
MOV [CSSAVE],AX
|
|
MOV [IPSAVE],DX
|
|
RET$5: RET
|
|
|
|
; Jump to program, setting up registers according to the
|
|
; save area. up to 10 breakpoint addresses may be specified.
|
|
|
|
GO:
|
|
CALL SETADD
|
|
XOR BX,BX
|
|
MOV DI,OFFSET DG:BPTAB
|
|
GO1:
|
|
CALL SCANP
|
|
JZ DEXEC
|
|
MOV BP,[CSSAVE]
|
|
CALL ADDRESS
|
|
MOV [DI],DX ; Save offset
|
|
MOV [DI+2],AX ; Save segment
|
|
ADD DI,5 ; Leave a little room
|
|
INC BX
|
|
CMP BX,1+BPMAX
|
|
JNZ GO1
|
|
MOV AX,5000H+"B" ; BP ERROR
|
|
JMP ERR
|
|
DEXEC:
|
|
MOV [BRKCNT],BX
|
|
MOV CX,BX
|
|
JCXZ NOBP
|
|
MOV DI,OFFSET DG:BPTAB
|
|
PUSH DS
|
|
SETBP:
|
|
LDS SI,ES:DWORD PTR [DI]
|
|
ADD DI,4
|
|
MOVSB
|
|
MOV BYTE PTR [SI-1],0CCH
|
|
LOOP SETBP
|
|
POP DS
|
|
NOBP:
|
|
MOV [TCOUNT],1
|
|
JMP DEXIT
|
|
|
|
SKIP_FILE:
|
|
MOV AH,CHAR_OPER
|
|
INT 21H
|
|
MOV [SWITCHAR],DL ; GET THE CURRENT SWITCH CHARACTER
|
|
FIND_DELIM:
|
|
LODSB
|
|
CALL DELIM1
|
|
JZ GOTDELIM
|
|
CALL DELIM2
|
|
JNZ FIND_DELIM
|
|
GOTDELIM:
|
|
DEC SI
|
|
RET
|
|
|
|
PREPNAME:
|
|
MOV ES,DSSAVE
|
|
PUSH SI
|
|
MOV DI,81H
|
|
COMTAIL:
|
|
LODSB
|
|
STOSB
|
|
CMP AL,13
|
|
JNZ COMTAIL
|
|
SUB DI,82H
|
|
XCHG AX,DI
|
|
MOV ES:(BYTE PTR [80H]),AL
|
|
POP SI
|
|
MOV DI,FCB
|
|
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
|
|
INT 21H
|
|
MOV BYTE PTR [AXSAVE],AL ; Indicate analysis of first parm
|
|
CALL SKIP_FILE
|
|
MOV DI,6CH
|
|
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
|
|
INT 21H
|
|
MOV BYTE PTR [AXSAVE+1],AL ; Indicate analysis of second parm
|
|
RET23: RET
|
|
|
|
|
|
; OPENS A XENIX PATHNAME SPECIFIED IN THE UNFORMATTED PARAMETERS
|
|
; VARIABLE [XNXCMD] SPECIFIES WHICH COMMAND TO OPEN IT WITH
|
|
;
|
|
; VARIABLE [HANDLE] CONTAINS THE HANDLE
|
|
; VARIABLE [EXTPTR] POINTS TO THE FILES EXTENSION
|
|
|
|
DELETE_A_FILE:
|
|
MOV BYTE PTR [XNXCMD],UNLINK
|
|
JMP SHORT OC_FILE
|
|
|
|
PARSE_A_FILE:
|
|
MOV BYTE PTR [XNXCMD],0
|
|
JMP SHORT OC_FILE
|
|
|
|
EXEC_A_FILE:
|
|
MOV BYTE PTR [XNXCMD],EXEC
|
|
MOV BYTE PTR [XNXOPT],1
|
|
JMP SHORT OC_FILE
|
|
|
|
OPEN_A_FILE:
|
|
MOV BYTE PTR [XNXCMD],OPEN
|
|
MOV BYTE PTR [XNXOPT],2 ; Try read write
|
|
CALL OC_FILE
|
|
JNC RET23
|
|
MOV BYTE PTR [XNXCMD],OPEN
|
|
MOV BYTE PTR [XNXOPT],0 ; Try read only
|
|
JMP SHORT OC_FILE
|
|
|
|
CREATE_A_FILE:
|
|
MOV BYTE PTR [XNXCMD],CREAT
|
|
|
|
OC_FILE:
|
|
PUSH DS
|
|
PUSH ES
|
|
PUSH AX
|
|
PUSH BX
|
|
PUSH CX
|
|
PUSH DX
|
|
PUSH SI
|
|
XOR AX,AX
|
|
MOV [EXTPTR],AX ; INITIALIZE POINTER TO EXTENSIONS
|
|
MOV AH,CHAR_OPER
|
|
INT 21H
|
|
MOV [SWITCHAR],DL ; GET THE CURRENT SWITCH CHARACTER
|
|
|
|
MOV SI,81H
|
|
|
|
OPEN1: CALL GETCHRUP
|
|
CALL DELIM2 ; END OF LINE?
|
|
JZ OPEN4
|
|
CALL DELIM1 ; SKIP LEADING DELIMITERS
|
|
JZ OPEN1
|
|
|
|
MOV DX,SI ; SAVE POINTER TO BEGINNING
|
|
DEC DX
|
|
OPEN2: CMP AL,"." ; LAST CHAR A "."?
|
|
JNZ OPEN3
|
|
MOV [EXTPTR],SI ; SAVE POINTER TO THE EXTENSION
|
|
OPEN3: CALL GETCHRUP
|
|
CALL DELIM1 ; LOOK FOR END OF PATHNAME
|
|
JZ OPEN4
|
|
CALL DELIM2
|
|
JNZ OPEN2
|
|
|
|
OPEN4: DEC SI ; POINT BACK TO LAST CHAR
|
|
PUSH [SI] ; SAVE TERMINATION CHAR
|
|
MOV BYTE PTR [SI],0 ; NULL TERMINATE THE STRING
|
|
|
|
MOV AL,[XNXOPT]
|
|
MOV AH,[XNXCMD] ; OPEN OR CREATE FILE
|
|
OR AH,AH
|
|
JZ OPNRET
|
|
MOV BX,OFFSET DG:EXEC_BLOCK
|
|
XOR CX,CX
|
|
INT 21H
|
|
MOV CS:[HANDLE],AX ; SAVE ERROR CODE OR HANDLE
|
|
|
|
OPNRET: POP [SI]
|
|
|
|
POP SI
|
|
POP DX
|
|
POP CX
|
|
POP BX
|
|
POP AX
|
|
POP ES
|
|
POP DS
|
|
RET
|
|
|
|
GETCHRUP:
|
|
LODSB
|
|
CMP AL,"a"
|
|
JB GCUR
|
|
CMP AL,"z"
|
|
JA GCUR
|
|
SUB AL,32
|
|
MOV [SI-1],AL
|
|
GCUR: RET
|
|
|
|
DELIM0: CMP AL,"["
|
|
JZ LIMRET
|
|
DELIM1: CMP AL," " ; SKIP THESE GUYS
|
|
JZ LIMRET
|
|
CMP AL,";"
|
|
JZ LIMRET
|
|
CMP AL,"="
|
|
JZ LIMRET
|
|
CMP AL,9
|
|
JZ LIMRET
|
|
CMP AL,","
|
|
JMP SHORT LIMRET
|
|
|
|
DELIM2: CMP AL,[SWITCHAR] ; STOP ON THESE GUYS
|
|
JZ LIMRET
|
|
CMP AL,13
|
|
LIMRET: RET
|
|
|
|
NAME:
|
|
CALL PREPNAME
|
|
MOV AL,BYTE PTR AXSAVE
|
|
MOV PARSERR,AL
|
|
PUSH ES
|
|
POP DS
|
|
PUSH CS
|
|
POP ES
|
|
MOV SI,FCB ; DS:SI points to user FCB
|
|
MOV DI,SI ; ES:DI points to DEBUG FCB
|
|
MOV CX,82
|
|
REP MOVSW
|
|
RET6: RET
|
|
|
|
BADNAM:
|
|
MOV DX,OFFSET DG:NAMBAD
|
|
JMP RESTART
|
|
|
|
IFHEX:
|
|
CMP BYTE PTR [PARSERR],-1 ; Invalid drive specification?
|
|
JZ BADNAM
|
|
CALL PARSE_A_FILE
|
|
MOV BX,[EXTPTR]
|
|
CMP WORD PTR DS:[BX],"EH" ; "HE"
|
|
JNZ RET6
|
|
CMP BYTE PTR DS:[BX+2],"X"
|
|
RET
|
|
|
|
IFEXE:
|
|
PUSH BX
|
|
MOV BX,[EXTPTR]
|
|
CMP WORD PTR DS:[BX],"XE" ; "EX"
|
|
JNZ RETIF
|
|
CMP BYTE PTR DS:[BX+2],"E"
|
|
RETIF: POP BX
|
|
RET
|
|
|
|
LOAD:
|
|
MOV BYTE PTR [RDFLG],READ
|
|
JMP SHORT DSKIO
|
|
|
|
DWRITE:
|
|
MOV BYTE PTR [RDFLG],WRITE
|
|
DSKIO:
|
|
MOV BP,[CSSAVE]
|
|
CALL SCANB
|
|
JNZ PRIMIO
|
|
JMP DEFIO
|
|
PRIMIO: CALL ADDRESS
|
|
CALL SCANB
|
|
JNZ PRMIO
|
|
JMP FILEIO
|
|
PRMIO: PUSH AX ; Save segment
|
|
MOV BX,DX ; Put displacement in proper register
|
|
MOV CX,1
|
|
CALL GETHEX ; Drive number must be 1 digit
|
|
PUSH DX
|
|
MOV CX,4
|
|
CALL GETHEX ; Logical record number
|
|
PUSH DX
|
|
MOV CX,3
|
|
CALL GETHEX ; Number of records
|
|
CALL GETEOL
|
|
MOV CX,DX
|
|
POP DX ; Logical record number
|
|
POP AX ; Drive number
|
|
CBW ; Turn off verify after write
|
|
MOV BYTE PTR DRVLET,AL ; Save drive in case of error
|
|
PUSH AX
|
|
PUSH BX
|
|
PUSH DX
|
|
MOV DL,AL
|
|
INC DL
|
|
MOV AH,GET_DPB
|
|
INT 21H
|
|
POP DX
|
|
POP BX
|
|
OR AL,AL
|
|
POP AX
|
|
POP DS ; Segment of transfer
|
|
JNZ DRVERRJ
|
|
CMP CS:BYTE PTR [RDFLG],WRITE
|
|
JZ ABSWRT
|
|
INT 25H ; Primitive disk read
|
|
JMP SHORT ENDABS
|
|
|
|
ABSWRT:
|
|
INT 26H ; Primitive disk write
|
|
ENDABS:
|
|
JNC RET0
|
|
DRVERRJ: JMP DRVERR
|
|
|
|
RET0:
|
|
POPF
|
|
RET
|
|
|
|
DEFIO:
|
|
MOV AX,[CSSAVE] ; Default segment
|
|
MOV DX,100H ; Default file I/O offset
|
|
CALL IFHEX
|
|
JNZ EXECHK
|
|
XOR DX,DX ; If HEX file, default OFFSET is zero
|
|
HEX2BINJ:JMP HEX2BIN
|
|
|
|
FILEIO:
|
|
; AX and DX have segment and offset of transfer, respectively
|
|
CALL IFHEX
|
|
JZ HEX2BINJ
|
|
EXECHK:
|
|
CALL IFEXE
|
|
JNZ BINFIL
|
|
CMP BYTE PTR [RDFLG],READ
|
|
JZ EXELJ
|
|
MOV DX,OFFSET DG:EXEWRT
|
|
JMP RESTART ; Can't write .EXE files
|
|
|
|
BINFIL:
|
|
CMP BYTE PTR [RDFLG],WRITE
|
|
JZ BINLOAD
|
|
CMP WORD PTR DS:[BX],4F00H + "C" ; "CO"
|
|
JNZ BINLOAD
|
|
CMP BYTE PTR DS:[BX+2],"M"
|
|
JNZ BINLOAD
|
|
EXELJ:
|
|
DEC SI
|
|
CMP DX,100H
|
|
JNZ PRER
|
|
CMP AX,[CSSAVE]
|
|
JZ OAF
|
|
PRER: JMP PERROR
|
|
OAF: CALL OPEN_A_FILE
|
|
JNC GDOPEN
|
|
MOV AX,exec_file_not_found
|
|
JMP EXECERR
|
|
|
|
GDOPEN: XOR DX,DX
|
|
XOR CX,CX
|
|
MOV BX,[HANDLE]
|
|
MOV AL,2
|
|
MOV AH,LSEEK
|
|
INT 21H
|
|
CALL IFEXE ; SUBTRACT 512 BYTES FOR EXE
|
|
JNZ BIN2 ; FILE LENGTH BECAUSE OF
|
|
SUB AX,512 ; THE HEADER
|
|
BIN2: MOV [BXSAVE],DX ; SET UP FILE SIZE IN DX:AX
|
|
MOV [CXSAVE],AX
|
|
MOV AH,CLOSE
|
|
INT 21H
|
|
JMP EXELOAD
|
|
|
|
NO_MEM_ERR:
|
|
MOV DX,OFFSET DG:TOOBIG
|
|
MOV AH,STD_CON_STRING_OUTPUT
|
|
INT 21H
|
|
JMP COMMAND
|
|
|
|
WRTFILEJ: JMP WRTFILE
|
|
NOFILEJ: JMP NOFILE
|
|
|
|
BINLOAD:
|
|
PUSH AX
|
|
PUSH DX
|
|
CMP BYTE PTR [RDFLG],WRITE
|
|
JZ WRTFILEJ
|
|
CALL OPEN_A_FILE
|
|
JC NOFILEJ
|
|
MOV BX,[HANDLE]
|
|
MOV AX,(LSEEK SHL 8) OR 2
|
|
XOR DX,DX
|
|
MOV CX,DX
|
|
INT 21H ; GET SIZE OF FILE
|
|
MOV SI,DX
|
|
MOV DI,AX ; SIZE TO SI:DI
|
|
MOV AX,(LSEEK SHL 8) OR 0
|
|
XOR DX,DX
|
|
MOV CX,DX
|
|
INT 21H ; RESET POINTER BACK TO BEGINNING
|
|
POP AX
|
|
POP BX
|
|
PUSH BX
|
|
PUSH AX ; TRANS ADDR TO BX:AX
|
|
ADD AX,15
|
|
MOV CL,4
|
|
SHR AX,CL
|
|
ADD BX,AX ; Start of transfer rounded up to seg
|
|
MOV DX,SI
|
|
MOV AX,DI ; DX:AX is size
|
|
MOV CX,16
|
|
DIV CX
|
|
OR DX,DX
|
|
JZ NOREM
|
|
INC AX
|
|
NOREM: ; AX is number of paras in transfer
|
|
ADD AX,BX ; AX is first seg that need not exist
|
|
CMP AX,CS:[PDB_block_len]
|
|
JA NO_MEM_ERR
|
|
MOV CXSAVE,DI
|
|
MOV BXSAVE,SI
|
|
POP DX
|
|
POP AX
|
|
|
|
RDWR:
|
|
; AX:DX is disk transfer address (segment:offset)
|
|
; SI:DI is length (32-bit number)
|
|
|
|
RDWRLOOP:
|
|
MOV BX,DX ; Make a copy of the offset
|
|
AND DX,000FH ; Establish the offset in 0H-FH range
|
|
MOV CL,4
|
|
SHR BX,CL ; Shift offset and
|
|
ADD AX,BX ; Add to segment register to get new Seg:offset
|
|
PUSH AX
|
|
PUSH DX ; Save AX,DX register pair
|
|
MOV WORD PTR [TRANSADD],DX
|
|
MOV WORD PTR [TRANSADD+2],AX
|
|
MOV CX,0FFF0H ; Keep request in segment
|
|
OR SI,SI ; Need > 64K?
|
|
JNZ BIGRDWR
|
|
MOV CX,DI ; Limit to amount requested
|
|
BIGRDWR:
|
|
PUSH DS
|
|
PUSH BX
|
|
MOV BX,[HANDLE]
|
|
MOV AH,[RDFLG]
|
|
LDS DX,[TRANSADD]
|
|
INT 21H ; Perform read or write
|
|
POP BX
|
|
POP DS
|
|
JC BADWR
|
|
CMP BYTE PTR [RDFLG],WRITE
|
|
JNZ GOODR
|
|
CMP CX,AX
|
|
JZ GOODR
|
|
BADWR: MOV CX,AX
|
|
STC
|
|
POP DX ; READ OR WRITE BOMBED OUT
|
|
POP AX
|
|
RET
|
|
|
|
GOODR:
|
|
MOV CX,AX
|
|
SUB DI,CX ; Request minus amount transferred
|
|
SBB SI,0 ; Ripple carry
|
|
OR CX,CX ; End-of-file?
|
|
POP DX ; Restore DMA address
|
|
POP AX
|
|
JZ RET8
|
|
ADD DX,CX ; Bump DMA address by transfer length
|
|
MOV BX,SI
|
|
OR BX,DI ; Finished with request
|
|
JNZ RDWRLOOP
|
|
RET8: CLC ; End-of-file not reached
|
|
RET
|
|
|
|
NOFILE:
|
|
MOV DX,OFFSET DG:NOTFND
|
|
RESTARTJMP:
|
|
JMP RESTART
|
|
|
|
WRTFILE:
|
|
CALL CREATE_A_FILE ; Create file we want to write to
|
|
MOV DX,OFFSET DG:NOROOM ; Creation error - report error
|
|
JC RESTARTJMP
|
|
MOV SI,BXSAVE ; Get high order number of bytes to transfer
|
|
CMP SI,000FH
|
|
JLE WRTSIZE ; Is bx less than or equal to FH
|
|
XOR SI,SI ; Ignore BX if greater than FH - set to zero
|
|
WRTSIZE:
|
|
MOV DX,OFFSET DG:WRTMES1 ; Print number bytes we are writing
|
|
CALL RPRBUF
|
|
OR SI,SI
|
|
JZ NXTBYT
|
|
MOV AX,SI
|
|
CALL DIGIT
|
|
NXTBYT:
|
|
MOV DX,CXSAVE
|
|
MOV DI,DX
|
|
CALL OUT16 ; Amount to write is SI:DI
|
|
MOV DX,OFFSET DG:WRTMES2
|
|
CALL RPRBUF
|
|
POP DX
|
|
POP AX
|
|
CALL RDWR
|
|
JNC CLSFLE
|
|
CALL CLSFLE
|
|
CALL DELETE_A_FILE
|
|
MOV DX,OFFSET DG:NOSPACE
|
|
JMP RESTARTJMP
|
|
CALL CLSFLE
|
|
JMP COMMAND
|
|
|
|
CLSFLE:
|
|
MOV AH,CLOSE
|
|
MOV BX,[HANDLE]
|
|
INT 21H
|
|
RET
|
|
|
|
EXELOAD:
|
|
POP [RETSAVE] ; Suck up return addr
|
|
INC BYTE PTR [NEWEXEC]
|
|
MOV BX,[USER_PROC_PDB]
|
|
MOV AX,DS
|
|
CMP AX,BX
|
|
JZ DEBUG_CURRENT
|
|
JMP FIND_DEBUG
|
|
|
|
DEBUG_CURRENT:
|
|
MOV AX,[DSSAVE]
|
|
DEBUG_FOUND:
|
|
MOV BYTE PTR [NEWEXEC],0
|
|
MOV [HEADSAVE],AX
|
|
PUSH [RETSAVE] ; Get the return address back
|
|
PUSH AX
|
|
MOV BX,CS
|
|
SUB AX,BX
|
|
PUSH CS
|
|
POP ES
|
|
MOV BX,AX
|
|
ADD BX,10H ; RESERVE HEADER
|
|
MOV AH,SETBLOCK
|
|
INT 21H
|
|
POP AX
|
|
MOV WORD PTR [COM_LINE+2],AX
|
|
MOV WORD PTR [COM_FCB1+2],AX
|
|
MOV WORD PTR [COM_FCB2+2],AX
|
|
|
|
CALL EXEC_A_FILE
|
|
JC EXECERR
|
|
CALL SET_TERMINATE_VECTOR ; Reset int 22
|
|
MOV AH,GET_CURRENT_PDB
|
|
INT 21H
|
|
MOV [USER_PROC_PDB],BX
|
|
MOV [DSSAVE],BX
|
|
MOV [ESSAVE],BX
|
|
MOV ES,BX
|
|
MOV WORD PTR ES:[PDB_exit],OFFSET DG:TERMINATE
|
|
MOV WORD PTR ES:[PDB_exit+2],DS
|
|
LES DI,[COM_CSIP]
|
|
MOV [CSSAVE],ES
|
|
MOV [IPSAVE],DI
|
|
MOV WORD PTR [DISADD+2],ES
|
|
MOV WORD PTR [DISADD],DI
|
|
MOV WORD PTR [ASMADD+2],ES
|
|
MOV WORD PTR [ASMADD],DI
|
|
MOV WORD PTR [DEFDUMP+2],ES
|
|
MOV WORD PTR [DEFDUMP],DI
|
|
MOV BX,DS
|
|
MOV AH,SET_CURRENT_PDB
|
|
INT 21H
|
|
LES DI,[COM_SSSP]
|
|
MOV AX,ES:[DI]
|
|
INC DI
|
|
INC DI
|
|
MOV [AXSAVE],AX
|
|
MOV [SSSAVE],ES
|
|
MOV [SPSAVE],DI
|
|
RET
|
|
|
|
EXECERR:
|
|
MOV DX,OFFSET DG:NOTFND
|
|
CMP AX,exec_file_not_found
|
|
JZ GOTEXECEMES
|
|
MOV DX,OFFSET DG:ACCMES
|
|
CMP AX,error_access_denied
|
|
JZ GOTEXECEMES
|
|
MOV DX,OFFSET DG:TOOBIG
|
|
CMP AX,exec_not_enough_memory
|
|
JZ GOTEXECEMES
|
|
MOV DX,OFFSET DG:EXEBAD
|
|
CMP AX,exec_bad_format
|
|
JZ GOTEXECEMES
|
|
MOV DX,OFFSET DG:EXECEMES
|
|
GOTEXECEMES:
|
|
MOV AH,STD_CON_STRING_OUTPUT
|
|
INT 21H
|
|
JMP COMMAND
|
|
|
|
HEX2BIN:
|
|
MOV [INDEX],DX
|
|
MOV DX,OFFSET DG:HEXWRT
|
|
CMP BYTE PTR [RDFLG],WRITE
|
|
JNZ RDHEX
|
|
JMP RESTARTJ2
|
|
RDHEX:
|
|
MOV ES,AX
|
|
CALL OPEN_A_FILE
|
|
MOV DX,OFFSET DG:NOTFND
|
|
JNC HEXFND
|
|
JMP RESTART
|
|
HEXFND:
|
|
XOR BP,BP
|
|
MOV SI,OFFSET DG:(BUFFER+BUFSIZ) ; Flag input buffer as empty
|
|
READHEX:
|
|
CALL GETCH
|
|
CMP AL,":" ; Search for : to start line
|
|
JNZ READHEX
|
|
CALL GETBYT ; Get byte count
|
|
MOV CL,AL
|
|
MOV CH,0
|
|
JCXZ HEXDONE
|
|
CALL GETBYT ; Get high byte of load address
|
|
MOV BH,AL
|
|
CALL GETBYT ; Get low byte of load address
|
|
MOV BL,AL
|
|
ADD BX,[INDEX] ; Add in offset
|
|
MOV DI,BX
|
|
CALL GETBYT ; Throw away type byte
|
|
READLN:
|
|
CALL GETBYT ; Get data byte
|
|
STOSB
|
|
CMP DI,BP ; Check if this is the largest address so far
|
|
JBE HAVBIG
|
|
MOV BP,DI ; Save new largest
|
|
HAVBIG:
|
|
LOOP READLN
|
|
JMP SHORT READHEX
|
|
|
|
GETCH:
|
|
CMP SI,OFFSET DG:(BUFFER+BUFSIZ)
|
|
JNZ NOREAD
|
|
MOV DX,OFFSET DG:BUFFER
|
|
MOV SI,DX
|
|
MOV AH,READ
|
|
PUSH BX
|
|
PUSH CX
|
|
MOV CX,BUFSIZ
|
|
MOV BX,[HANDLE]
|
|
INT 21H
|
|
POP CX
|
|
POP BX
|
|
OR AX,AX
|
|
JZ HEXDONE
|
|
NOREAD:
|
|
LODSB
|
|
CMP AL,1AH
|
|
JZ HEXDONE
|
|
OR AL,AL
|
|
JNZ RET7
|
|
HEXDONE:
|
|
MOV [CXSAVE],BP
|
|
MOV BXSAVE,0
|
|
RET
|
|
|
|
HEXDIG:
|
|
CALL GETCH
|
|
CALL HEXCHK
|
|
JNC RET7
|
|
MOV DX,OFFSET DG:HEXERR
|
|
RESTARTJ2:
|
|
JMP RESTART
|
|
|
|
GETBYT:
|
|
CALL HEXDIG
|
|
MOV BL,AL
|
|
CALL HEXDIG
|
|
SHL BL,1
|
|
SHL BL,1
|
|
SHL BL,1
|
|
SHL BL,1
|
|
OR AL,BL
|
|
RET7: RET
|
|
|
|
|
|
CODE ENDS
|
|
END DEBCOM2
|