	page	,132
	title	dispregs - display registers as set by loader
	name	dispregs
;****************************************************************
;* module name = dispregs
;*
;* copyright(C) 1984	Skip Gilbrech
;*			90 Lexington Ave. #10-G
;*			New York, NY 10016
;*			212-685-0551
;*
;* author = skip gilbrech
;* date written = 01/13/84
;*
;* environment:
;*  system = ibm pc (dos 2.0 - should work on any version)
;*  processor = microsoft 8086 macro assembler
;*
;* This program may be freely copied/altered for any non-commercial
;* purpose but may not be sold or used in any way as part of any
;* profit-making venture without permission of the author.
;* (i.e., in the unlikely event that any money is made off this,
;* I want some of it...)
;*
;* This little program was inspired by some of the recent discussion
;* on the SIG concerning starting conditions (i.e. register & flag
;* settings) encountered by files loaded under DEBUG versus those
;* encountered by files loaded by COMMAND.COM.	It was noted that
;* certain programs worked under one but not under the other, and I
;* realized that I had always assumed things were the same either way...
;*
;* It seems, however, that although the differences aren't great, they
;* do exist.  It is, of course, foolish to rely on register and flag
;* settings made by someone else, but that doesn't mean it isn't done.
;*
;* The only assumptions made about register settings in this program
;* are that:
;*
;*   -- CS:IP points to the beginning of the code (hard to avoid
;*	that assumption...)
;*   -- DS:0 contains an INT 21H instruction (will run fine without
;*	it, but will have trouble exiting...)
;*
;* By the way, this can be made into a .COM or .EXE file by changing
;* the equate below.  It was necessary to make two versions as the
;* two types of files are loaded differently.  To make a .COM file,
;* use EXE2BIN after you get the obnoxious 'no stack segment' warning
;* from LINK.  Of course, the .EXE register settings for CS,IP,SS and
;* SP are peculiar to this file, as they are defined by the linker and
;* passed to dos in the .EXE header.
;*
;****************************************************************
	page
;****************************************************************
;*
;*	constants
;*
;****************************************************************

false		equ	0
true		equ	not false

make_com	equ	true		; if true, make .COM file

if not make_com 			; else make .EXE file
make_exe	equ	true
else
make_exe	equ	false
endif

lf	equ	10			; line feed
cr	equ	13			; carriage return

dosint		equ	21h		; int. number for dos functions
print_string	equ	9		; dos print string function

;****************************************************************
;*
;*	macro
;*
;****************************************************************

msg_mac macro	TEXT,FORMAT_ROUTINE
	mov	dx,offset TEXT
	mov	ah,print_string
	int	dosint
	pop	ax
	call	FORMAT_ROUTINE
	endm

;****************************************************************
;*
;*	stack segment if making .exe file
;*
;****************************************************************

if make_exe
stack	segment stack
dw	128 dup (?)
stack	ends
endif

	page
;****************************************************************
;*
;*	code (and data) segment
;*
;****************************************************************

code	segment
	assume	cs:code,ds:nothing,es:nothing,ss:nothing

if make_com
	org	100h		; for com file
endif

reg_disp proc far		; set up for far return to dos

	jmp	mainline	; jump to program code

; strings for formatting the register display:

msg_cs		db	cr,lf,'CS ==>$'
msg_ds		db	'  DS ==>$'
msg_es		db	'  ES ==>$'
msg_ss		db	'  SS ==>$'
msg_ax		db	cr,lf,'AX ==>$'
msg_bx		db	'  BX ==>$'
msg_cx		db	'  CX ==>$'
msg_dx		db	'  DX ==>$'
msg_si		db	cr,lf,'SI ==>$'
msg_di		db	'  DI ==>$'
msg_bp		db	'  BP ==>$'
msg_sp		db	'  SP ==>$'
msg_ip		db	cr,lf,'IP ==>$'

; buffers for outputting digits and printing flag settings:

digit_buf	db	'      $'
msg_flags	db	cr,lf,'FLAGS ==>  - - - - O D I T S Z - A - P - C'
		db	cr,lf,'           $'
flagbuf 	db	'                               ',cr,lf,'$'

save_ds 	dw	?
save_es 	dw	?
save_ss 	dw	?
save_sp 	dw	?
save_ax 	dw	?
save_fl 	dw	?

	page
;****************************************************************
;*
;*	reg_disp mainline
;*
;****************************************************************

mainline	label near

	mov	cs:save_ds,ds		; save DS & ES
	mov	cs:save_es,es		;
	mov	cs:save_ss,ss		; save SS:SP so we can get
	mov	cs:save_sp,sp		;  value of flags
	mov	cs:save_ax,ax		; save AX before using

; early 8088's might bomb here if interrupts aren't disabled, but I can't
; think of any way to save the initial flag settings without using the
; stack, and I'm not assuming the stack is valid, so....

	mov	ax,cs			; set SS to CS
	mov	ss,ax			;
	mov	sp,offset short_stack	; we can now use the stack

	pushf				; save flags before we change them
	pop	cs:save_fl		;

; set up for far return to dos:

	push	ds			; ptr to psp (either .com or .exe)
	sub	ax,ax			; offset 0
	push	ax			; push it

	mov	ax,cs			; set DS & ES to CS for addressing data
	mov	ds,ax			;
	mov	es,ax			;

	assume ds:code,es:code		; tell MASM

; save all original register values on the stack

	push	save_fl 		;
	mov	ax,offset reg_disp	; starting value of IP -- if this was
	push	ax			; wrong, we'll never get here
	push	save_sp 		;
	push	bp			; (not changed)
	push	di			; (not changed)
	push	si			; (not changed)
	push	dx			; (not changed)
	push	cx			; (not changed)
	push	bx			; (not changed)
	push	save_ax 		;
	push	save_ss 		;
	push	save_es 		;
	push	save_ds 		;
	push	cs			; (not changed)

; now display everything

	msg_mac 	msg_cs, hexdig_out
	msg_mac 	msg_ds, hexdig_out
	msg_mac 	msg_es, hexdig_out
	msg_mac 	msg_ss, hexdig_out
	msg_mac 	msg_ax, hexdig_out
	msg_mac 	msg_bx, hexdig_out
	msg_mac 	msg_cx, hexdig_out
	msg_mac 	msg_dx, hexdig_out
	msg_mac 	msg_si, hexdig_out
	msg_mac 	msg_di, hexdig_out
	msg_mac 	msg_bp, hexdig_out
	msg_mac 	msg_sp, hexdig_out
	msg_mac 	msg_ip, hexdig_out
	msg_mac 	msg_flags, prt_flags

	ret		; far return to offset 0 in psp

reg_disp	endp

	page
;****************************************************************
;*
;*	hexdig_out	output value in AX in hex to console
;*
;****************************************************************

hexdig_out	proc	near

	push	ax
	push	dx
	push	di

	mov	di,offset digit_buf	; string buffer address
	push	di			; save for later
	add	di,5			; point to last digit
	std				; set for auto decrement
	push	ax			; save value in AH
	call	hexdig_out0		; store two least significant digits
	pop	ax			; restore value in AH
	mov	al,ah			; get two most sig. digits
	call	hexdig_out0		; store them
	pop	dx			; pt DX to beginning of string
	mov	ah,print_string 	; dos function number
	int	dosint			;

	pop	di
	pop	dx
	pop	ax
	ret

hexdig_out0:
	push	ax			; save al for other half of digit
	and	al,0fh			; strip off high digit
	call	hexdig_out1		; store lower digit
	pop	ax			; get al back for high digit
	shr	al,1			; shift into lower digit
	shr	al,1			;
	shr	al,1			;
	shr	al,1			;
					; then store lower digit
hexdig_out1:
	or	al,30h			; convert 0-9 to ASCII
	cmp	al,3ah			;
	jb	hexdig_out2		;
	add	al,7			; convert 10-15 to A-F

hexdig_out2:
	stosb				; store digit in buffer & pt to next
	ret				; most significant digit

hexdig_out	endp

	page
;****************************************************************
;*
;*	prt_flags	print flag settings (in AX) as 1 or 0
;*
;****************************************************************

prt_flags	proc near

	push	ax
	push	cx
	push	dx
	push	di
	mov	dx,ax			; save flag settings in DX
	mov	cx,16			; repeat for each bit
	mov	di,offset flagbuf	; set DI to buffer for flags
	push	di			; save for dos call
	cld				; auto-increment
pf_loop:
	rol	dx,1			; get flag bit in bit 0
	mov	al,dl			; move bit to AL
	and	al,1			; isolate it
	add	al,'0'                  ; make ascii
	stosb				; store char. in buf, bump ptr
	inc	di			; bump again past space
	loop	pf_loop 		; repeat while bits remain

	pop	dx			; restore address of buffer
	mov	ah,print_string 	;
	int	dosint			;

	pop	di
	pop	dx
	pop	cx
	pop	ax
	ret

prt_flags	endp

	even		; put stack on word boundary

short_stack	equ	$ + 100h

code	ends

end	reg_disp
