;       SCCSID = @(#)bvfrtrc.asm	6.1 90/11/16
;SCCSID = @(#)bvfrtrc.asm	6.2 90/01/23
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
	PAGE	58,132
	TITLE	BvsRtrc.Asm -- Base Video Subsystem Video Retrace Subroutines

BVSNSEG SEGMENT PARA PUBLIC 'DATA'
BVSNSEG ENDS

BVS2SEG SEGMENT BYTE PUBLIC 'CODE'
	ASSUME	CS:BVS2SEG

;/*********************** START OF SPECIFICATIONS ***********************/
;/*									*/
;/* SOURCE FILE NAME:  BvsRtrc.Asm					*/
;/*									*/
;/* DESCRIPTIVE NAME:  Base Video Subsystem Video Retrace Subroutines	*/
;/*									*/
;/* COPYRIGHT:	na							*/
;/*									*/
;/* STATUS:	na							*/
;/*									*/
;/* NOTES:   Executes on level 2					*/
;/*									*/
;/*    DEPENDENCIES:  none						*/
;/*									*/
;/*    RESTRICTIONS:  none						*/
;/*									*/
;/*    PATCH LABEL:   na						*/
;/*									*/
;/* ENTRY POINT: RBufferUpdate						*/
;/*									*/
;/* EXTERNAL REFERENCES: None						*/
;/*									*/
;/************************ END OF SPECIFICATIONS ************************/

	.xlist
	INCLUDE bvfcb.inc		;BVS Data Structures
	INCLUDE struc.inc		;Structured Macros
	.list

horzwait macro				;Wait for horizontal retrace
	.repeat
	    in	    al,dx
	    test    al,1		;Loop until retrace appears
	.until	z
	cli				;Disable interrupts
	.repeat
	    in	    al,dx
	    test    al,1		;Wait until it passes
	.until	nz
	endm

allwait macro				;Wait for all retraces
	.repeat
	    in	    al,dx
	    test    al,9
	.until	z			;Wait until no retrace of any kind
	cli				;Disable interrupts
	.repeat
	    in	    al,dx
	    test    al,1
	.until	nz			;Wait for start of horiz retrace
	endm

;/*********************** START OF SPECIFICATIONS ***********************/
;/*									*/
;/* SUBROUTINE NAME:  RBufferUpdate					*/
;/*									*/
;/* DESCRIPTIVE NAME:  Base Video Subsystem Retrace Buffer Update Subs	*/
;/*									*/
;/* FUNCTION:	Movement of data from the user's buffer to the PVB      */
;/*		while checking for retrace signals.			*/
;/*									*/
;/* NOTES:  Execute on Level 2 via single Call Gate without stack parms */
;/*									*/
;/* ENTRY POINT:  RBufferUpdate 					*/
;/*   LINKAGE:	  Far Call from BufferUpdate as noted below		*/
;/*									*/
;/* Subroutine Index:  MvBSSA	Move CX bytes Skip SI Attrs		*/
;/*			from BvsReadCharStr				*/
;/*									*/
;/* Subroutine Index:  MvBSDA	Move CX bytes Skip DI Attrs		*/
;/*			from BvsWrtCharStr				*/
;/*									*/
;/* Subroutine Index:  MvBWCA	Move CX bytes With AH Attr		*/
;/*			from BvsWrtCharStrAtt				*/
;/*									*/
;/* Subroutine Index:  MvWCSD	Move CX words from SI to DI		*/
;/*			from BvsScrollUp, BvsScrollDn,			*/
;/*			     BvsScrollLf, BvsScrollRt,			*/
;/*			     BvsReadCellStr, BvsWrtCellStr		*/
;/*									*/
;/* Subroutine Index:  StBCSD	Store CX bytes from SI at DI		*/
;/*			from BvsWrtNAttr, BvsWrtNChar			*/
;/*									*/
;/* Subroutine Index:  StWCSD	Store CX words from SI at DI		*/
;/*			from BvsScrollUp, BvsScrollDn,			*/
;/*			     BvsScrollLf, BvsScrollRt			*/
;/*									*/
;/* INPUT:	CX    = Length of string or number of times		*/
;/*		DS:SI = Source ptr or data in SI			*/
;/*		ES:DI = Destination ptr 				*/
;/*		AH    = Constant attr for BWCA				*/
;/*		BX    = Subroutine index				*/
;/*									*/
;/* EXIT-NORMAL:  AX = 0						*/
;/*									*/
;/* EXIT-ERROR:  None							*/
;/*									*/
;/* EFFECTS:  None							*/
;/*									*/
;/* INTERNAL REFERENCES:  None						*/
;/*   ROUTINES:  MoveRBSSA, MoveRBSDA, MoveRBWCA, MoveRBCSD,		*/
;/*		 StoreRBCSD, StoreRWCSD 				*/
;/*									*/
;/* EXTERNAL REFERENCES:  None						*/
;/*   ROUTINES:  None							*/
;/*									*/
;/************************ END OF SPECIFICATIONS ************************/

;Bgnsub MoveRXXXX
;: Do CX > 0
;: : Wait for video retrace
;: : Copy one byte from *SrcPtr++ to *DestPtr++
;: : CX = CX - 1
;: Enddo
;Endsub

;Bgnsub StoreRXXXX
;: Do CX > 0
;: : Wait for video retrace
;: : Fill one byte of *DestPtr++ with item
;: : CX = CX - 1
;: Enddo
;Endsub

RBufferUpdate PROC FAR
	PUBLIC	RBufferUpdate
	push	dx
	push	ds
	mov	dx,bvsnseg
	mov	ds,dx			;Get PPBVSCB ptr
	mov	ds,ds:ppbvs_bvssel	;Get BVSCB ptr
	mov	dx,ds:bvs_physport	;Get physical port addr
	add	dx,6			;Adjust to status port
	pop	ds

	push	bp
	push	sp
	mov	bp,sp
	.if	<bp eq [bp]>		;This is not a 286
	    Call    CS:XRTable[BX]	;Invoke the XT MoveR/StoreR routines
	.else

	    Call    CS:RSubTbl[BX]	;Invoke the 286 MoveR/StoreR routines

	.endif
	pop	bp			;Throw away pushed SP
	pop	bp

	pop	dx
	RET
RBufferUpdate ENDP

;Table of Retrace Subroutines
RSubTbl dw	MoveRBSSA
	dw	MoveRWCSD
	dw	MoveRWCSD
	dw	MoveRWCSD
	dw	MoveRBSDA
	dw	MoveRBWCA
	dw	StoreRBCSD
	dw	StoreRWCSD

MoveRBSDA PROC	NEAR			;Move CX bytes skip DI attrs
	test	cl,1
	.if	NZ
	    horzwait			;Wait for horizontal retrace
	    movsb			;Move the first byte
	    sti 			;Enable interrupts
	    inc     di
	.endif

	shr	cx,1
	.if	NCXZ
	    .repeat
		horzwait		;Wait for horizontal retrace
		movsb
		inc	di
		movsb			;Move two bytes
		sti			;Enable interrupts
		inc	di
	    .loop
	.endif
	RET
MoveRBSDA ENDP

MoveRBSSA PROC	NEAR			;Move CX bytes skip SI attrs
	test	cl,1
	.if	NZ
	    horzwait			;Wait for horizontal retrace
	    movsb			;Move the first byte
	    sti 			;Enable interrupts
	    inc     si
	.endif

	shr	cx,1
	.if	NCXZ
	    .repeat
		horzwait		;Wait for horizontal retrace
		movsb
		inc	si
		movsb			;Move two bytes
		sti			;Enable interrupts
		inc	si
	    .loop
	.endif
	RET
MoveRBSSA ENDP

MoveRBWCA PROC	NEAR			;Move CX bytes with AH attr
	test	cl,1
	.if	NZ
	    horzwait			;Wait for horizontal retrace
	    lodsb
	    stosw			;Move the first byte with attr
	    sti 			;Enable interrupts
	.endif

	shr	cx,1
	.if	NCXZ
	    .repeat
		horzwait		;Wait for horizontal retrace
		lodsb
		stosw
		lodsb
		stosw			;Move two bytes with attr
		sti			;Enable interrupts
	    .loop
	.endif
	RET
MoveRBWCA ENDP

MoveRWCSD PROC	NEAR			;Move CX words from DS:SI to ES:DI
	.if	NCXZ
	    .repeat
		allwait 		;Wait for all retraces
		movsw			;Move word to buffer
		dec	cx
		.repeat
		    in	    al,dx
		    test    al,1
		.leave	z		;Retraces have passed
		    test    al,8
		    .if     nz		;Vertical retrace has begun

			mov	ax,312	;Move data in chunks
			cmp	ax,cx
			.if	a
			    mov     ax,cx
			.endif
			sub	cx,ax
			push	cx
			mov	cx,ax	;Get length of this chunk
			rep	movsw	;Move character and attribute
			pop	cx
		    .leave
		    .endif
		.until			;Until no more retraces
		sti			;Enable interrupts again
		or	cx,cx
	    .until  z			;Until CX exhausted
	.endif
	RET
MoveRWCSD ENDP

StoreRBCSD PROC NEAR			;Store CX bytes from SI at ES:DI
	test	cl,1
	.if	NZ
	    horzwait			;Wait for horizontal retrace
	    mov     ax,si
	    stosb			;Fill the first word with Cell
	    sti 			;Enable interrupts
	    inc     di
	.endif

	shr	cx,1
	.if	NCXZ
	    .repeat
		horzwait		;Wait for horizontal retrace
		mov	ax,si
		stosb
		inc	di
		stosb			;Fill two words with Cell
		sti			;Enable interrupts
		inc	di
	    .loop
	.endif
	RET
StoreRBCSD ENDP

StoreRWCSD PROC NEAR			;Store CX words from SI at ES:DI
	test	cl,1
	.if	NZ
	    horzwait			;Wait for horizontal retrace
	    mov     ax,si
	    stosw			;Fill the first word with Cell
	    sti 			;Enable interrupts
	    dec     cx
	.endif
	.if	NCXZ
	    .repeat
		allwait 		;Wait for all retraces
		mov	ax,si
		stosw
		stosw			;Fill the first word with Cell
		dec	cx
		dec	cx
		.repeat
		    in	    al,dx
		    test    al,1
		.leave	z		;Retraces have passed
		    test    al,8
		    .if     nz		;Vertical retrace has begun

			mov	ax,624	;Move data in chunks
			cmp	ax,cx
			.if	a
			    mov     ax,cx
			.endif
			sub	cx,ax
			push	cx
			mov	cx,ax	;Get length of this chunk
			mov	ax,si
			rep	stosw	;Fill the first word with Cell
			pop	cx
		    .leave
		    .endif
		.until			;Until no more retraces
		sti			;Enable interrupts again
		or	cx,cx
	    .until  z			;Until CX exhausted
	.endif
	RET
StoreRWCSD ENDP

; PC/XT Retrace routines

XRTable dw	MoveXRBSSA
	dw	MoveXRWCSD
	dw	MoveXRWCSD
	dw	MoveXRWCSD
	dw	MoveXRBSDA
	dw	MoveXRBWCA
	dw	StoreXRBCSD
	dw	StoreXRWCSD

MoveXRBSDA PROC NEAR			;Move CX bytes skip DI attrs
	.if	NCXZ
	    .repeat
		horzwait		;Wait for horizontal retrace
		movsb			;Move one byte
		sti			;Enable interrupts
		inc	di
	    .loop
	.endif
	RET
MoveXRBSDA ENDP

MoveXRBSSA PROC NEAR			;Move CX bytes skip SI attrs
	.if	NCXZ
	    .repeat
		horzwait		;Wait for horizontal retrace
		movsb			;Move one byte
		sti			;Enable interrupts
		inc	si
	    .loop
	.endif
	RET
MoveXRBSSA ENDP

MoveXRBWCA PROC NEAR			;Move CX bytes with AH attr
	.if	NCXZ
	    .repeat
		horzwait		;Wait for horizontal retrace
		movsb			;Move one char
		sti			;Enable interrupts

		horzwait		;Wait for horizontal retrace
		mov	al,ah
		stosb			;Store one attribute
		sti			;Enable interrupts
	    .loop
	.endif
	RET
MoveXRBWCA ENDP

MoveXRWCSD PROC NEAR			;Move CX words from DS:SI to ES:DI
	.if	NCXZ
	    pushf
	    pop     ax
	    and     ah,04h
	    .if     nz			;Decrement flag set
		inc	si
		inc	di		;Adjust for decrement flag
	    .endif

	    add     cx,cx		;Convert words to bytes
	    .repeat
		allwait 		;Wait for all retraces
		movsb			;Move one character to buffer
		sti			;Enable interrupts again
	    .loop			;Until CX exhausted

	    and     ah,ah
	    .if     nz			;Decrement flag set
		dec	si
		dec	di		;Adjust for decrement flag
	    .endif
	.endif
	RET
MoveXRWCSD ENDP

StoreXRBCSD PROC NEAR			;Store CX bytes from SI at ES:DI
	.if	NCXZ
	    .repeat
		horzwait		;Wait for horizontal retrace
		mov	ax,si
		stosb			;Fill one byte from SI
		sti			;Enable interrupts
		inc	di
	    .loop
	.endif
	RET
StoreXRBCSD ENDP

StoreXRWCSD PROC NEAR			;Store CX words from SI at ES:DI
	.if	NCXZ
	    push    si
	    pushf
	    pop     ax
	    and     ah,04h
	    .if     nz			;Decrement flag set
		xchg	ax,si
		xchg	al,ah
		xchg	ax,si		;Switch order of bytes
		inc	di		;Adjust for decrement flag
	    .endif

	    .repeat
		horzwait		;Wait for horizontal retrace
		mov	ax,si
		stosb			;Fill the character
		sti			;Enable interrupts

		horzwait		;Wait for horizontal retrace
		mov	al,ah
		stosb			;Fill the attribute
		sti			;Enable interrupts
	    .loop

	    pushf
	    pop     ax
	    and     ah,04h
	    .if     nz			;Decrement flag set
		dec	di		;Adjust for decrement flag
	    .endif
	    pop     si
	.endif
	RET
StoreXRWCSD ENDP

BVS2SEG ENDS
	END

