title	ldebcom Debugger Commands
;	SCCSID = @(#)ldebcom.asm	11.4 89/03/16

; Routines to perform debugger commands except ASSEMble and UASSEMble

.xlist
.xcref
include ldebequ.inc
.cref
.list

include ldebseg.inc

NOREGL		equ	8
PROMPT		=	">"


DBDATA	segment

	extrn	_DEFDUMP:word, _INDEX:word
	extrn	_DISADD:byte, _NSEG:word
	extrn	_AWORD:byte
	extrn	_OPBUF:byte

	extrn	_pTXT:word

	extrn	sawctlc:byte
	extrn	_lbf:byte
	extrn	_ERRMES:byte
	extrn	_REGTAB:byte
	extrn	_SREG:byte, _SEGTAB:word, _REGDIF:word
	extrn	_RegSA:word
	extrn	_SYNERR:byte

	extrn	_StackTop:word

BYTEBUF db	BUFLEN	dup (?) 	; Table used by LIST

; Flags are ordered to correspond with the bits of the flag
; register, most significant bit first, zero if bit is not
; a flag. First 16 entries are for bit set, second 16 for
; bit reset.

FLAGTAB 	dw	0
		dw	0
		dw	0
		dw	0
		db	"OV"
		db	"DN"
		db	"EI"		; "STI"
		dw	0
		db	"NG"
		db	"ZR"
		dw	0
		db	"AC"
		dw	0
		db	"PE"
		dw	0
		db	"CY"
		dw	0
		dw	0
		dw	0
		dw	0
		db	"NV"
		db	"UP"		; "CLD"
		db	"DI"
		dw	0
		db	"PL"
		db	"NZ"
		dw	0
		db	"NA"
		dw	0
		db	"PO"
		dw	0
		db	"NC"

TOTREG		db	13

DumpFlags	dw	1		; default to byte dump

DBDATA	ends

DBCODE	segment

	public	_COMMAND
	public	_GETEOL, _PERR, _PERROR
	public	_DISPREG, _ERR

	extrn	_HEXCHK:near, _GetByte:near, _DSRANGE:near, _DEFAULT:near
	extrn	_IN:near, _OUT:near, _CRLF:near, _OUTDI:near, _OUTSI:near
	extrn	_ScanP:near, _SkipB:near, _GetChr:near, _GetChrI:near
	extrn	_BLANK:near, _TAB:near, _RPRBUF:near, _OUTpc:near
	extrn	_ADDRESS:near, _HEX:near, _BACKUP:near

	extrn	_GetWord:near
	extrn	_INBUF:near
	extrn	_OUT16:near
	extrn	_DISASLN:near
	extrn	_PRINTMES:near

	extrn	_GO:near
	extrn	_UNASSEM:near, _ASSEM:near
	extrn	_Ptrace:near, _TRACE:near, _BreakPoint:near


SCOMAND:
	MOV	[_pTXT],Offset ds:_lbf.lbuff
	MOV	[_lbf.lbuff],CR
_COMMAND:
	CLD
	MOV	AX,CS
	MOV	DS,AX
	MOV	ES,AX
	MOV	SS,AX
	MOV	SP,OFFSET ds:_StackTop
	mov	[sawctlc],0
GoPrompt:
	CALL	_GetChrI		; Look for ";" & advance
	CMP	AL,";"
	JE	GotCmd1 		; Brif more commands on this line
	MOV	AL,PROMPT
	CALL	_OUT
	CALL	_INBUF			; Get command line
	jmp	GotCmd
; From now and throughout command line processing, [_pTXT] points
; to next character in command line to be processed.

GotCmd1:inc	_pTXT			; advance past semicolon
GotCmd: CALL	_GetChrI		; Get 1st non-Blank & advance
	JZ	GoPrompt		; Null command?

; Prepare command letter for table lookup

	SUB	AL,"A"			; Low end range check
	JB	ERR1
	CMP	AL,"Z"-"A"		; Upper end range check
	JA	ERR1
	SHL	AL,1			; Times two
	CBW				; Now a 16-bit quantity
	XCHG	BX,AX			; In BX we can address with it
	CALL	CS:[BX+COMTAB]		; Execute command
	JMP	_COMMAND		; Get next command
ERR1:	JMP	_PERR

; Command Table. Command letter indexes into table to get
; address of command. _PERR prints error for no such command.

COMTAB	dw	IGROUP:_ASSEM 		; A
	dw	IGROUP:_BreakPoint	; B
	dw	IGROUP:COMPARE		; C
	dw	IGROUP:DUMP		; D
	dw	IGROUP:ENTER		; E
	dw	IGROUP:FILL		; F
	dw	IGROUP:_GO		; G
	dw	IGROUP:HEXADD 		; H
	dw	IGROUP:INPUT		; I
	dw	IGROUP:_PERR		; J
	dw	IGROUP:_PERR		; K
	dw	IGROUP:_PERR		; L
	dw	IGROUP:MOVE		; M
	dw	IGROUP:_PERR		; N
	dw	IGROUP:OUTPUT 		; O
	dw	IGROUP:_Ptrace		; P
	dw	IGROUP:_PERR		; Q
	dw	IGROUP:REG		; R
	dw	IGROUP:SEARCH 		; S
	dw	IGROUP:_TRACE 		; T
	dw	IGROUP:_UNASSEM		; U
	dw	IGROUP:_PERR		; V
	dw	IGROUP:_PERR		; W
	dw	IGROUP:_ReBoot		; x
	dw	IGROUP:_PERR		; Y
	dw	IGROUP:_PERR		; z


; Dump an area of memory in both hex and ASCII

DUMP:
;;	MOV	BP,[_RegSA.DSSAV]
	mov	si,[_pTXT]
	mov	di,1			; (DI) = 1 implies dump bytes
	cmp	byte ptr[si],'B'
	jz	short dmp10
	add	di,di			; (DI) = 2 implies dump words
	cmp	byte ptr[si],'W'
	jz	short dmp10
	add	di,di			; (DI) = 4 implies dump dwords
	cmp	byte ptr[si],'D'
	jz	short dmp10
	mov	di,[DumpFlags]
	jmp	short dmp20

dmp10:	inc	[_pTXT]			; advance past dump modifier
	mov	[DumpFlags],di
dmp20:	push	di			; save dump flag
	mov	bp,[_DEFDUMP+2]
	mov	cx,128
	mov	di,offset ds:_DEFDUMP
	call	_DEFAULT		; Get range if specified
	mov	ds,ax			; Set segment
	mov	si,dx			; SI has displacement in segment
	pop	di			; restore dump flag
ROW:
	call	_OUTSI			; Print address at start of line
	push	si			; Save address for ASCII dump
	call	_BLANK
BYTE0:
	call	_BLANK			; Space between bytes
BYTE1:
	cmp	cx,di
	jb	short dmp50
	cmp	di,2			; dump bytes, words or dwords?
	jb	short dmp50		; jmp if dumping bytes
	lodsw				; get first word
	mov	dx,ax
	jz	short dmp40		; jmp if dumping words
	push	dx			; save offset
	lodsw				; get segment
	mov	dx,ax
	call	_OUT16			; display segment
	mov	al,":"
	call	_OUT
	pop	dx			; restore offset
dmp40:	call	_OUT16			; and display it
	jmp	short dmp55

dmp50:	lodsb				; Get byte to dump
	call	_HEX			; and display it
dmp55:	pop	dx			; DX has start addr. for ASCII dump
	sub	cx,di			; Drop loop count
	jz	Ascii			; If through do ASCII dump
	cmp	ss:[sawctlc],0
	jnz	Ascii
	mov	ax,dx
	add	ax,16
	cmp	ax,si			; On 16-byte boundary?
	je	ENDROW
	push	dx			; Didn't need ASCII addr. yet
	sub	ax,8
	cmp	ax,si			; 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

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

; 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
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	_OUTpc			; Print ASCII character
	LOOP	ASCDMP			; CX times
	POP	CX			; Restore overall dump length
	MOV	ES:[_DEFDUMP],SI
	MOV	ES:[_DEFDUMP+2],DS	; Save last address as default
	CALL	_CRLF			; Print CR/LF and return
	RET


; Hex addition and subtraction

if SMALL

HEXADD		equ	ERR1

else

HEXADD:
	CALL	_GetWord
	MOV	DI,DX
	CALL	_GetWord
	CALL	_GETEOL
	mov	si,dx
	ADD	DX,DI
	mov	al,'+'
	call	_out
	CALL	_OUT16
	CALL	_BLANK
	CALL	_BLANK
	mov	dx,di
	sub	dx,si
	mov	al,'-'
	call	_out
	CALL	_OUT16
	CALL	_BLANK
	CALL	_BLANK
	mov	ax,di
	mul	si
	xchg	ax,dx
	push	ax
	mov	al,'*'
	call	_out
	CALL	_OUT16
	CALL	_BLANK
	pop	dx
	CALL	_OUT16
	CALL	_BLANK
	CALL	_BLANK
	mov	ax,0FFFFh
	mov	dx,ax
	or	si,si
	jz	hexa1
	mov	ax,di
	xor	dx,dx
	div	si
	xchg	ax,dx
hexa1:
	push	ax
	mov	al,'/'
	call	_out
	CALL	_OUT16
	CALL	_BLANK
	pop	dx
	CALL	_OUT16
	JMP	_CRLF
endif

; 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.

if SMALL

MOVE		equ	ERR1

else

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
	cld
RET1:	RET

endif

; 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.

if SMALL

FILL		equ	ERR1

else

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 ds: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
endif

; Search a specified area of memory for given list of bytes.
; Print address of first byte of each match.

if SMALL

SEARCH		equ	ERR1

else

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 ds: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
endif

; 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	_GetChr 		; Get first character of param
	push	ax
	CALL	_HEXCHK 		; Is it in hex?
	pop	ax
	JC	STRINGCHK		; If not, could be a string
	CALL	_GetByte		; Get the byte value
	MOV	[BX],DL 		; Add to list
	INC	BX
GRET:	CLC				; Parameter was OK
	RET
STRINGCHK:
	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
	CALL	_SkipB
	mov	si, _pTXT
STRNGLP:
	lodsb				; Next char of string
	mov	_pTXT,si
	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 ds:BYTEBUF	; Put byte list in the byte buffer
LISTLP:
	CALL	LISTITEM		; Process a parameter
	JNC	LISTLP			; If OK, try for more
	SUB	BX,OFFSET ds: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:
	PUSH	AX
	CALL	_GetChr 		; Skip blanks
	POP	AX
	JNZ	_PERROR 		; Better be a RETURN
RET3:	RET

; Command error. [_pTXT] has been incremented beyond the
; command letter so it must decremented for the
; error pointer to work.

_PERR:
	DEC	[_pTXT]

; Syntax error. [_pTXT] 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:
	MOV	SI,[_pTXT]
	SUB	SI,OFFSET ds:(_lbf.lbuff-1); How many char processed so far?
	MOV	CX,SI			; Parameter for TAB in CX
	CALL	_TAB			; Directly below bad char
	MOV	SI,OFFSET ds:_SYNERR	; Error message

; Print error message and abort to command level

PRINT:
	MOV	DX,SI
	CALL	_RPRBUF
	JMP	SCOMAND

; 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 ds: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 up to 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,[_RegSA.DSSAV]	; Set default segment to DS
	CALL	_ADDRESS
	PUSH	AX			; Save for later
	PUSH	DX
	CALL	_GetChr 		; 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
GET8BIT:
	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,CR			; All done with command?
	JZ	EOL
	CMP	AL," "			; Go to next address
	JZ	NEXT
	MOV	AL,8
	CALL	_OUT			; Back over 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	GET8BIT 		; 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


_DISPREG:
	MOV	SI,OFFSET ds:_REGTAB
	MOV	BX,OFFSET ds:_RegSA.AXSAV
	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,[_RegSA.IPSAV]
	MOV	word ptr [_DISADD],AX
	PUSH	AX
	MOV	AX,[_RegSA.CSSAV]
	MOV	word ptr [_DISADD+2],AX
	PUSH	AX
	MOV	[_NSEG],-1
	CALL	_DISASLN
	PUSH	DI
	MOV	AX,OFFSET ds:_OPBUF+34
	CMP	DI,AX
	JAE	LONGLIN
	MOV	byte ptr [DI]," "
LONGLIN:
	MOV	SI,OFFSET ds:_OPBUF
	CALL	_PRINTMES		; and the operand buffer
	POP	DI
	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	Dl,[BX]
	MOV	Dh,[BX+1]
	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
	CALL	_GetChrI
	MOV	DL,AL
	CALL	_GetChrI
	MOV	DH,AL
	JZ	FLAG
	CALL	_GETEOL
	CMP	DH," "
	JZ	FLAG
	MOV	DI,OFFSET ds:_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	_GetChr
	JZ	RET4
	CALL	_GetWord
	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
	XOR	BX,BX
	MOV	DX,[_RegSA.FSAV]
GETFLG:
	CALL	_GetChrI
	JZ	SAVCHG
	MOV	AH,AL
	CALL	_GetChrI
	XCHG	AH,AL
	JZ	FLGERR
	MOV	DI,OFFSET ds: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	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 ds:_ERRMES
	JMP	PRINT
SAVCHG:
	MOV	[_RegSA.FSAV],DX
	RET
FLGERR:
	MOV	AX,4600H+"B"		; BF ERROR
	JMP	SHORT FERR
DISPFLAGS:
	MOV	SI,OFFSET ds:FLAGTAB
	MOV	CX,16
	MOV	DX,[_RegSA.FSAV]
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

if SMALL

INPUT		equ	ERR1

else

INPUT:
	CALL	_GetWord		; Get port number in DX
	CALL	_GETEOL
	IN	AL,DX			; Variable port input
	CALL	_HEX			; And display
	JMP	_CRLF
endif

; Output a value to specified port.

if SMALL

OUTPUT		equ	ERR1

else

OUTPUT:
	CALL	_GetWord		; Get port number
	PUSH	DX			; Save while we get data
	CALL	_GetByte		; 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

endif

if SMALL

COMPARE 	equ	ERR1

else

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
endif

;***	_Reboot command (X)
;
;	Does a soft reboot on a IBM AT.
;
;	Modified : June 4 1986 DJG
;	Use the keyboard to reset the processor.
;	Works in real or protected mode.
;

KEYBPORT	equ	64h
RESET		equ	0F0h		; Magic reset value (i.e. bit 0 == 0)

_ReBoot proc
	xor	ax,ax
	mov	es,ax
	mov	word ptr es:[472h],1234H
	mov	al,RESET
	out	KEYBPORT, al
rbt90:	hlt
	jmp	short rbt90		; Better safe than sorry!!!
_ReBoot endp

DBCODE	ends
	end
