PAGE 60,132 TITLE DEBCOM1.ASM - PART1 DEBUGGER COMMANDS PC DOS ;/* ; * Microsoft Confidential ; * Copyright (C) Microsoft Corporation 1991 ; * All Rights Reserved. ; */ ;======================= START OF SPECIFICATIONS ========================= ; ; MODULE NAME: DECOM1.asm ; ; DESCRIPTIVE NAME: DEBUGGING TOOL ; ; FUNCTION: PROVIDES USERS WITH A TOOL FOR DEBUGGING PROGRAMS. ; ; ENTRY POINT: ANY CALLED ROUTINE ; ; INPUT: NA ; ; EXIT NORMAL: NA ; ; EXIT ERROR: NA ; ; INTERNAL REFERENCES: ; ; EXTERNAL REFERENCES: ; ; ROUTINE: DEBCOM2 - CONTAINS ROUTINES CALLED BY DEBUG ; DEBCOM3 - CONTAINS ROUTINES CALLED BY DEBUG ; DEBASM - CONTAINS ROUTINES CALLED BY DEBUG ; DEBUASM - CONTAINS ROUTINES CALLED BY DEBUG ; DEBMES - CONTAINS ROUTINES CALLED BY DEBUG ; ; NOTES: THIS MODULE IS TO BE PREPPED BY SALUT WITH THE "PR" OPTIONS. ; LINK DEBUG+DEBCOM1+DEBCOM2+DEBCOM3+DEBASM+DEBUASM+DEBERR+ ; DEBCONST+DEBDATA+DEBMES ; ; REVISION HISTORY: ; ; AN000 VERSION 4.00 - REVISIONS MADE RELATE TO THE FOLLOWING: ; ; - IMPLEMENT DBCS HANDLING DMS:6/17/87 ; - IMPLEMENT MESSAGE RETRIEVER DMS:6/17/87 ; - IMPLEMENT > 32MB SUPPORT DMS:6/17/87 ; ; COPYRIGHT: "MS DOS DEBUG UTILITY" ; "VERSION 4.00 (C) COPYRIGHT 1988 Microsoft" ; "LICENSED MATERIAL - PROPERTY OF Microsoft " ; ;======================= END OF SPECIFICATIONS =========================== ; Routines to perform debugger commands except ASSEMble and UASSEMble IF1 ;%out COMPONENT=DEBUG, MODULE=DEBCOM1 ENDIF .XLIST .XCREF include syscall.inc ; cas -- missing equates include version.inc ; cas -- missing equates INCLUDE DOSSYM.INC INCLUDE debug.inc .CREF .LIST CODE SEGMENT PUBLIC BYTE CODE ENDS CONST SEGMENT PUBLIC BYTE EXTRN SYNERR_PTR:BYTE EXTRN DISPB:WORD,DSIZ:BYTE,DSSAVE:WORD IF SYSVER EXTRN CIN:DWORD,PFLAG:BYTE ENDIF CONST ENDS CSTACK SEGMENT STACK CSTACK ENDS DATA SEGMENT PUBLIC BYTE EXTRN DEFLEN:WORD,BYTEBUF:BYTE,DEFDUMP:BYTE EXTRN ARG_BUF:BYTE,ARG_BUF_PTR:BYTE EXTRN ONE_CHAR_BUF:BYTE,ONE_CHAR_BUF_PTR:WORD DATA ENDS DG GROUP CODE,CONST,CSTACK,DATA CODE SEGMENT PUBLIC BYTE 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,ENTERDATA,FILL,SEARCH,DEFAULT ifdef JAPAN public SETDUMPMODE extrn test_lead:near endif IF SYSVER PUBLIC IN EXTRN DISPREG:NEAR,DEVIOCALL:NEAR ENDIF EXTRN CRLF:NEAR,OUTDI:NEAR,OUTSI:NEAR,SCANP:NEAR EXTRN SCANB:NEAR,BLANK:NEAR,TAB:NEAR,COMMAND:NEAR EXTRN HEX:NEAR,BACKUP:NEAR EXTRN PRINTF_CRLF:NEAR,HEX_ADDRESS_ONLY:NEAR,HEX_ADDRESS_STR:NEAR EXTRN STD_PRINTF: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,UPPER_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 ; Removing this instruction allows 0 FFFF to valid range 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 short 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 ifdef JAPAN ; ; Set Dump mode to Kanji or Ascii ; dump_mode db 0 dbcs_flag db 0 dbcs_adj db 0 SETDUMPMODE: call scanp ; get parameter jz dm_err ; if none lodsb cmp al,'K' ; is it for Kanji mode jnz @f ; no call geteol mov cs:dump_mode,1 ; set Kanji mode jmp short dm_ret @@: cmp al,'A' ; is it for Ascii mode jnz @f ; no call geteol mov cs:dump_mode,0 ; set Ascii mode jmp short dm_ret @@: dm_err: jmp PERR dm_ret: ret endif ; Dump an area of memory in both hex and ASCII DUMP: ifdef JAPAN mov cs:dbcs_flag,0 mov cs:dbcs_adj,0 endif MOV BP,[DSSAVE] MOV CX,DISPB MOV DI,OFFSET DG:DEFDUMP CALL DEFAULT ; Get range if specified MOV DS,AX ; Set segment ASSUME DS:NOTHING MOV SI,DX ; SI has displacement in segment PUSH SI ; save SI away MOV AL,DSIZ XOR AH,AH XOR AX,-1 AND SI,AX ; convert to para number MOV DI,OFFSET DG:ARG_BUF ; Build the output str in arg_buf CALL OUTSI ; display location POP SI ; get SI back ; Determine where the registers display should begin. MOV AX,SI ; move offset MOV AH,3 ; spaces per byte AND AL,DSIZ ; convert to real offset MUL AH ; 3 char positions per byte of output OR AL,AL ; at beginning? JZ INROW ; if so, then no movement. PUSH CX MOV CX,AX CALL TAB POP CX INROW: PUSH SI ; Save address for ASCII dump 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 ASCII ; If through do ASCII dump MOV AX,SI TEST AL,DSIZ ; On row boundary? JZ ENDROW PUSH DX ; Didn't need ASCII addr. yet TEST AL,7 ; On 8-byte boundary? JNZ BYTE0 MOV AL,CHAR_MINUS ; Mark every 8 bytes with "-" STOSB JMP SHORT BYTE1 ENDROW: CALL ASCII ; Show it in ASCII MOV DI,OFFSET DG:ARG_BUF ; Build the output str in arg_buf CALL OUTSI ; Get the address at start of line JMP INROW ; Loop until count is zero ; Produce a dump of the ascii text characters. We take the current SI which ; contains the byte after the last one dumped. From this we determine how ; many spaces we need to output to get to the ascii column. Then we look at ; the beginning address of the dump to tsee how many spaces we need to indent. ASCII: PUSH CX ; Save count of remaining bytes ; Determine how many spaces to go until the ASCII column. MOV AX,SI ; get offset of next byte DEC AL AND AL,DSIZ INC AL ; AX now has the number of bytes that we have displayed: 1 to Dsiz+1. ; Compute characters remaining to be displayed. We *always* put the ASCII ; dump in column 51 (or whereever) SUB AL,10H ; get negative of number DEC AL ; NEG AL ; convert to positive CBW ; convert to word ; 3 character positions for each byte displayed. MOV CX,AX SHL AX,1 ADD CX,AX ; Compute indent for ascii dump MOV AX,DX AND AL,DSIZ XOR AH,AH ADD CX,AX ; Tab over CALL TAB ; Set up for true dump MOV CX,SI MOV SI,DX SUB CX,SI ASCDMP: LODSB ; Get ASCII byte to dump ifdef JAPAN cmp cs:dbcs_flag,1 jz set_dbcs ; if it was lead byte cmp cs:dbcs_flag,2 jnz @f ; if it was not tail byte mov cs:dbcs_flag,0 ; reset @@: call test_lead jnc @f ; if this is not lead byte cmp byte ptr [si],CHAR_BLANK jae set_dbcs ; if tail byte is not control corde mov al,CHAR_PERIOD jmp short @f set_dbcs: inc cs:dbcs_flag @@: cmp cs:dump_mode,1 jnz @f ; if not Kanji mode cmp cs:dbcs_adj,1 jnz kanjiprt ; if no need to adjust mov al,' ' ; tail byte is displayed already mov cs:dbcs_adj,0 jmp short kanjiprt @@: endif CMP AL,CHAR_RUBOUT JAE NOPRT ; Don't print RUBOUT or above ifdef JAPAN kanjiprt: endif CMP AL,CHAR_BLANK JAE PRIN ; print space through RUBOUT-1 NOPRT: MOV AL,CHAR_PERIOD ; If unprintable character PRIN: STOSB LOOP ASCDMP ; CX times ifdef JAPAN cmp cs:dump_mode,1 jnz @f ; if not Kanji mode cmp cs:dbcs_flag,1 jnz @f ; if not ended with lead byte mov al,[si] ; get tail byte stosb mov cs:dbcs_adj,1 @@: endif MOV AL,0 STOSB PUSH DS PUSH CS POP DS ASSUME DS:DG CALL HEX_ADDRESS_STR CALL CRLF POP DS ASSUME DS:NOTHING POP CX ; Restore overall dump len MOV WORD PTR [DEFDUMP],SI MOV WORD PTR [DEFDUMP+WORD],DS ; Save last address as def RET ASSUME DS:DG ; 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 (sam 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-1 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 w 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 BIGRNG: SUB CX,BX ; How much bigger is area than 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 r 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 LO 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 TTEST ; Continue search if no match DEC DI ; Match address CALL OUTDI ; Print it INC DI ; Restore search address CALL HEX_ADDRESS_ONLY ; Print the addresss CALL CRLF TTEST: 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: This routine calculates the binary representation of an address ; entered in ASCII by a user. GETHX has been modified to provide ; support for sector addresses > 32mb. To do this the bx register ; has been added to provide a 32 bit address. BX is the high word ; and DX is the low word. For routines that rely on DX for a 16 ; bit address, the use of BX will have no effect. ; ; Date : 6/16/87 ;========================================================================= GETHX: CALL SCANP GETHX1: XOR DX,DX ; Initialize the number xor bx,bx ;an000;initialize high word for ; sector address 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? call ADDRESS_32_BIT ;an000;multiply by 32 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 is a hex digit and convert it to binary if it ; is. Carry set if not. HEXCHK: SUB AL,CHAR_ZERO ; 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 push bx ;an000;save it - we stomp it CALL GETHEX ; Get the byte value pop bx ;an000;restore it 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,SINGLE_QUOTE ; String? JZ STRING CMP AL,DOUBLE_QUOTE ; 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,CR ; 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 MOV DI,OFFSET DG:ARG_BUF ; CALL TAB ; Directly below bad char MOV BYTE PTR [DI],0 ; nul terminate the tab MOV DX,OFFSET DG:SYNERR_PTR ; Error message ; Print error message and abort to command level PRINT: CALL PRINTF_CRLF 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,UPPER_S JZ SEGREG MOV CX,4 CALL GETHX JC ADRERR MOV AX,BP ; Get default segment CMP BYTE PTR [SI],CHAR_COLON 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 ; SEGLET DB "CSED" MOV CX,4 REPNE SCASB JNZ ADRERR INC SI INC SI SHL CX,1 MOV BX,CX CMP BYTE PTR [SI],CHAR_COLON JNZ ADRERR PUSH [BX+DSSAVE] JMP SHORT GETDISP SEGLET DB "CSED" ; First letter of each of the segregs: CS,SS,ES,DS ; 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 buffer 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. ENTERDATA: 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 PUSH DI PUSH ES PUSH DS POP ES MOV DI,OFFSET DG:ARG_BUF CALL BLANK XOR AL,AL STOSB CALL HEX_ADDRESS_STR POP ES POP DI GETBYTE: MOV AL,ES:[DI] ; Get current value PUSH DI PUSH ES PUSH DS POP ES MOV DI,OFFSET DG:ARG_BUF CALL HEX ; And display it MOV AL,CHAR_PERIOD STOSB XOR AL,AL STOSB MOV DX,OFFSET DG:ARG_BUF_PTR CALL STD_PRINTF POP ES POP DI LOOK_AGAIN: MOV CX,2 ; Max of 2 digits in new value MOV DX,0 ; Intial new value GETDIG: CALL INPT ; 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 INPT ; Get command character NOHEX: CMP AL,CHAR_BACKSPACE ; Backspace JZ BS CMP AL,CHAR_RUBOUT ; RUBOUT JZ RUB CMP AL,CHAR_MINUS ; Back up to previous address JZ PREV CMP AL,CR ; All done with command? JZ EOL CMP AL,CHAR_BLANK ; Go to next address JZ NEXT MOV AL,CHAR_BACKSPACE CALL OUT_CHAR ; Back up over illegal character CALL BACKUP JCXZ DWAIT JMP SHORT GETDIG RUB: MOV AL,CHAR_BACKSPACE CALL OUT_char BS: CMP CL,2 ; CX=2 means nothing typed yet JZ PUTDOT ; Put back the dot we backed up over 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 PUTDOT: MOV AL,CHAR_PERIOD CALL OUT_CHAR JMP LOOK_AGAIN ; 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 PUSH DI MOV DI,OFFSET DG:ARG_BUF PUSH ES PUSH DS POP ES CALL TAB XOR AL,AL STOSB MOV DX,OFFSET DG:ARG_BUF_PTR CALL STD_PRINTF POP ES POP DI MOV AX,DI ; Next memory address AND AL,7 ; Check for 8-byte boundary JZ NEWROW ; Take 8 per line JMP GETBYTE 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 INPT: ;*** change for build - label to inpt PUSH DS PUSH SI LDS SI,CS:[CIN] MOV AH,4 CALL DEVIOCALL POP SI POP DS CMP AL,3 JNZ NOTCNTC INT VEC_CTRL_BREAK ;23H NOTCNTC: CMP AL,UPPER_P - CHAR_AT_SIGN JZ PRINTON CMP AL,UPPER_N - CHAR_AT_SIGN JZ PRINTOFF CALL OUT_CHAR RET PRINTOFF: PRINTON: NOT [PFLAG] JMP SHORT IN ELSE INPT: ; Change label for build MOV AH,Std_Con_Input ;OPTION=1, STANDARD CONSOLE INPUT INT 21H RET ENDIF OUT_CHAR: PUSH DI PUSH DX PUSH ES PUSH DS POP ES MOV DI,OFFSET DG:ONE_CHAR_BUF STOSB MOV AL,0 STOSB MOV DX,OFFSET DG:ONE_CHAR_BUF_PTR CALL STD_PRINTF POP ES POP DX POP DI RET ;========================================================================= ; ADDRESS_32_BIT: This routine will build an address for 32bit sector ; addressibility. BX will be the high word, with DX being ; the low word. ; ; Inputs : DX/BX - registers to contain 32bit sector address ; DX & BX are both initialized to 0 on first call to routine. ; ; Outputs: DX/BX - registers to contain 32bit sector address ; ; Date : 6/16/87 ;========================================================================= ADDRESS_32_BIT proc near ;an000;perform 32 bit address ; creation push cx ;an000;save affected regs. mov cx,04h ;an000;initialize to ; nibble shift ; $do ;an000;while cx not= 0 $$DO1: cmp cx,00h ;an000;are we done? ; $leave e ;an000;yes, quit loop JE $$EN1 shl bx,1 ;an000;shift bx 1 bit shl dx,1 ;an000;shift dx 1 bit ; $if c ;an000;did low word carry JNC $$IF3 or bx,01h ;an000;set bit 0 of high word ; $endif ;an000; $$IF3: dec cx ;an000;decrease counter ; $enddo ;an000;end while loop JMP SHORT $$DO1 $$EN1: or dl, al ;an000;overlay low word ; bits 0-3 with next ; portion of the address pop cx ;an000;restore affected regs. ret ;an000;return to caller ADDRESS_32_BIT endp ;an000;end proc CODE ENDS END DEBCOM1