

page	58,132
;******************************************************************************
	title	PRINT.ASM - Protected Mode Print Routines
;******************************************************************************
;
;   (C) Copyright MICROSOFT Corp. 1986
;
;   Title:    MEMMD.EXE - MICROSOFT Expanded Memory Manager 386 DEBUG Driver
;
;   Module:   PRINT.ASM - Protected Mode Print Routines
;
;   Version:  0.04
;
;   Date:     January 31, 1986
;
;   Author:
;
;******************************************************************************
;
;   Change log:
;
;     DATE    REVISION			DESCRIPTION
;   --------  --------	-------------------------------------------------------
;   01/31/86  Original
;   05/12/86  A	Cleanup and segment reorganization
;   06/28/86  0.02	Name changed from MEMM386 to MEMM
;   07/05/86  0.04	Moved to DCODE segment
;   07/06/86  0.04	moved data to DDATA segment
;
;******************************************************************************
;
;   Functional Description:
;
;******************************************************************************
.lfcond 				; list false conditionals
.386p

	public	PrintString
	public	PrintHex
	public	kputc
	public	RowCol
	public	IsReal

NAME	print

;**	print - cga simple print routines
;
	include VDMseg.inc
	include VDMsel.inc
	include desc.inc

;***	IsReal - determine mode of cpu
;
;	This routine is useful when writing dual mode code.
;	It returns with 'Z' = 1 if the cpu is in real mode,
;	otherwise 'Z' = 0.
;
;	ENTRY	DUAL MODE
;
;	EXIT	'Z' = 1 (protected mode), 0 (real mode)
;
;	USES	flags
;
_TEXT	 segment

	assume	cs:_TEXT, ds:nothing, es:nothing, ss:nothing

IsReal	proc	near

	push	ax
	smsw	ax
	xor	al, 0ffh
	and	al, 1
	pop	ax
	ret				; returns with flags set

IsReal	endp

_TEXT	 ends

;***	kputc - write character/attribute to screen
;
;	This is a simple character output routine. It does not
;	interleave writes to video memory with the 6845. It
;	does not update the cursor position. It does not understand
;	anything except a CGA in 80x25 text mode.
;
;	ENTRY	PROTECTED MODE
;		AX - character-attribute to write
;		DS - kernel data selector
;
;	EXIT	none - character written
;
;	USES	AX, flags
;

_DATA	 segment
RowCol	dw	0
_DATA	 ends

CR	equ	0dh				; carriage return
LF	equ	0ah				; line feed
TAB	equ	9				; tab
BS	equ	8				; backspace

COLOUR_PARA	equ	0b800h

_TEXT	 segment

	assume	cs:_TEXT, ds:_DATA, es:nothing, ss:nothing

kputc	proc	far

	push	bx				; save callers regs
	push	cx
	push	dx
	push	si
	push	di
	push	es
	push	ds

	call	IsReal				; need dual mode access
	jnz	kp10
	mov	dx, VDMD_GSEL			; selector for protected mode
	jmp	kp11
kp10:
	mov	dx, seg _DATA			 ; para for real mode
kp11:
	push	dx				; save this segment for later

	mov	ds, dx				; DS -> data segment
	mov	dx, ds:[RowCol] 		; DX = current row/col

	cmp	al, CR				; is character a CR?
	jne	kp1

	mov	dl, 0				; yes, go to column 0
	jmp	kp3				; jump to common code
kp1:

	cmp	al, LF				; is character a LF?
	jne	kp2

	inc	dh				; yes, go to next row
	jmp	kp3				; jump to common code
kp2:

	cmp	al, TAB 			; is it a tab
	jne	kp12
	and	dl, 0f8h			; mask off low 3 bits (8 ch)
	add	dl, 8				; move to next tab position
	jmp	kp3				; jmp to common code
kp12:

	cmp	al, BS				; is it backspace
	jne	kp13
	dec	dl				; back up one column
	jmp	kp3				; goto common code
kp13:
;	Must be ordinary character. Write it to screen, update position

	push	ax			; save char/attr

	mov	al, dh			; AL = row
	mov	ah, 80			; multiplier, 80 char per row
	mul	ah			; AX = cell at start of row
	mov	bh, 0
	mov	bl, dl			; BX = column
	add	bx, ax			; BX = cell
	shl	bx, 1			; BX = byte offset of cell

	call	IsReal			; bi-modal access to screen
	jnz	kp6
	mov	ax, COLOUR_GSEL 	; screen selector for protected mode
	jmp	kp7
kp6:
	mov	ax, COLOUR_PARA 	; screen para for real mode
kp7:
	mov	es, ax			; ES -> screen

	pop	es:[bx] 		; write character
	inc	dl			; update column
kp3:
;	Common code, first check for line wrap:

	cmp	dl, 80			; beyond rhs of screen?
	jl	kp4
	mov	dl, 0			; go to col 0
	inc	dh			; and move to next line
kp4:
;	Now check for scroll needed:

	cmp	dh, 25			; are we off end of screen?
	jl	kp5

;	Now scroll screen

	call	IsReal			; bi-modal access to screen
	jnz	kp8
	mov	ax, COLOUR_GSEL 	; screen selector for protected mode
	jmp	kp9
kp8:
	mov	ax, COLOUR_PARA 	; screen para for real mode
kp9:
	mov	ds, ax			; DS -> screen
	mov	es, ax			; ES -> screen

	mov	di, 0			; ES:DI = copy destination
	mov	si, 160 		; DS:SI = copy source
	mov	cx, 2000-80		; copy word count
	cld
	rep	movsw			; scroll

;	Blank bottom line

	mov	al, ' '
	mov	ah, 7			; AX = blank character

	mov	cx, 80			; number of cells to blank
	mov	di, 4000-160		; ES:DI = start point
	rep	stosw

;	Update position

	mov	dh, 24			; new row
kp5:
	pop	ds			; set DS to data again
	mov	ds:[RowCol], dx 	; update row/col

;	call	SetCursor

	pop	ds			; restore regs
	pop	es
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx

	ret

kputc	endp
_TEXT	 ends


;***	SetCursor - updates cursor position
;
;	This routine reprograms the 6845 cursor position, and
;	stores the new cursor position in the ROM bios data area.
;
;	ENTRY	DUAL MODE
;		DH, DL = row, col
;
;	EXIT	cursor updated
;
;	USES	ax, bx, cx, flags
;

CRT_COLS	equ	04ah
CURSOR_POSN	equ	050h
CRT_START	equ	04eh
ADDR_6845	equ	063h

_TEXT	 segment

	assume	cs:_TEXT, ds:_DATA, es:nothing, ss:nothing

SetCursor	proc	near

	push	ds
	mov	bx, 40h
	mov	ds, bx

;	Save new position in BIOS data area

	mov	ds:[CURSOR_POSN], dx

;	Calculate offset on screen

	mov	al, dh				; row
	mul	byte ptr ds:[CRT_COLS]		; row * cols
	mov	bl, dl				; bl = column
	mov	bh, 0				; bx = column
	add	ax, bx				; ax = offset in screen
	sal	ax, 1				; double for attribute bytes
	mov	cx, ds:[CRT_START]		; cx = start point of screen
	add	cx, ax				; cx = offset of cursor
	sar	cx, 1				; convert to char count only

;	Now program 6845

	mov	al, 14				; 6845 register
	mov	dx, ds:[ADDR_6845]		; base port #
	out	dx, al
	inc	dx
	jmp	short $+2

	mov	al, ch
	out	dx, al
	dec	dx
	jmp	short $+2

	mov	al, 15
	out	dx, al
	inc	dx
	jmp	short $+2

	mov	al, cl
	out	dx, al

	pop	ds

	ret

SetCursor	endp
_TEXT		 ends


;***	PrintString - prints a message on console
;
;	This routine calls the "kernel" to print a string
;	one character at a time.
;
;	ENTRY	286 PROTECTED MODE
;		DS - DATA3_SEL
;		ES - DATA3_SEL
;		SI - offset in DS of null terminated string to print
;
;	EXIT	String printed
;
;	USES	Flags
;

_TEXT	 segment

	assume	cs:_TEXT, ds:nothing, es:nothing, ss:nothing

PrintString	proc	near

	cld					; set up for string ops
	push	si				; save callers regs
	push	ax

pr1:						; loop printing until null
	lodsb					; al = char to print
	and	al, al				; terminator ?
	je	pr2
	mov	ah, 7				; attribute

	db	9ah				; far call
	dw	offset _TEXT:kputc		 ; offset
	dw	VDMC_GSEL			; selector

	jmp	pr1				; back for more
pr2:
	pop	ax				; restore callers regs
	pop	si

	ret

PrintString	endp

_TEXT	 ends

;***	Hex2String
;
;	Convert content of AX into 4 Hex digits string at ES:DI
;
;	ENTRY	AX	value to convert
;		ES:DI	storage string location
;

_TEXT	 segment

	assume	cs:_TEXT, ds:nothing, es:nothing, ss:nothing

PutHexChar	proc	near

	cmp	al,9
	ja	PHC_AF
	add	al,30h
	jmp	PHC_exit
PHC_AF:
	add	al,(41h - 0ah)
PHC_exit:
	push	ax
	mov	ah,7
	db	9ah				; far call
	dw	offset _TEXT:kputc		; offset
	dw	VDMC_GSEL			; selector
	pop	ax
	ret

PutHexChar	endp

PrintHex	proc	near

	cld

	xchg	al,ah
	push	ax
	shr	al,4
	call	PutHexChar
	pop	ax
	and	al,0fh
	call	PutHexChar
	xchg	al,ah
	push	ax
	shr	al,4
	call	PutHexChar
	pop	ax
	and	al,0fh
	call	PutHexChar

	ret

PrintHex	endp

_TEXT	 ends

	end
