TITLE scrn2.asm

;	AUTHOR  Tim Spencer - Compuserve [73657,1400]
;	DATE	March 15, 1987

_TEXT 	SEGMENT BYTE PUBLIC 'CODE'
_TEXT	ENDS

_DATA 	SEGMENT WORD PUBLIC 'DATA'

SCRN	STRUC		; screen data structure - defined in video.h
off	dw	0	; offset (cursor position) 
seg	dw	0	; screen buffer address
port	dw	0	; status port address
attrib	dw	0	; attribute to use 
cgacrd	dw	0	; retrace checking enabled if not zero
SCRN 	ENDS

_DATA	ENDS

DGROUP	GROUP _DATA
	ASSUME CS:_TEXT, DS:DGROUP, SS:DGROUP, ES:NOTHING


_TEXT	SEGMENT BYTE PUBLIC 'CODE'

;-----------------------------------------------------------------------;
; scrn_puts - MSC callable routine for printing a string directly to 	;
;	      the screen buffer.					;
;									;
; Usage:	scrn_puts(string, attribute, &structure_name);		;
;-----------------------------------------------------------------------;
_DATA	SEGMENT
scrn_puts_args STRUC		; args as pushed by calling program
	dw	0		; saved bp value
	dw	0		; return address
str_ptr	dw	0		; address of string
sstruc	dw	0		; pointer to SCRN structure
scrn_puts_args ENDS
_DATA	ENDS

	PUBLIC _scrn_puts

_scrn_puts	PROC	NEAR
	push	bp			;set up frame pointer
	mov	bp,sp		
	push	di
	push	si
	mov	si,[bp].str_ptr		; get the string pointer 
        mov	bx,[bp].sstruc 		; get pointer to SCRN structure
	les	di,dword ptr[bx].off	; put offset in di, buffer addr in es   
	mov	ch,byte ptr[bx].attrib	; put attribute in cx
	mov	dx,[bx].port		; get status port address

load_one:
	lodsb				; load a char and advance str ptr
	or	al,al			; is it null ?
	jz	puts_exit		; yes, lovely chatting. Chow babe.
	mov	cl,al			; no, save in cl for a few millisecs
	cmp	[bx].cgacrd, 0		; cga card present?
	jnz	swait1			; yes...go wait
	mov	ax,cx			; no.
	stosw				; write it
	jmp	short load_one		; as fast as you can!
swait1:
        in      al, dx                  ; wait for end of retrace
        shr     al, 1                   ; test horizontal trace bit
        jc      swait1			; loop if still tracing
        cli                             ; disable writus interuptus
swait2:
        in      al, dx                  ; now wait until the very moment
        shr     al, 1                   ; when the next retrace begins
        jnc     swait2			; still waiting...
        mov     al,cl			; load the char into al for stosb
        stosb				; write it and update pointer
        sti                             ; enable interrupts again
swait3:
        in      al, dx                  ; repeat these steps for the attribute
        shr     al, 1
        jc      swait3
        cli                             
swait4:
        in      al, dx                  
        shr     al, 1                   
	jnc     swait4
        mov     al,ch			; load the attribute
        stosb
        sti                             
	jmp	short load_one		; and get another

puts_exit:
	mov	[bx].off,di 		; save new offset ( cur pos )
	pop	si
	pop	di
	pop	bp
	ret
_scrn_puts	ENDP



;-----------------------------------------------------------------------;
; scrn_putca - MSC callable function to print a char and attribute	;
;	       directly to the screen buffer. The logical cursor	;
;	       position IS UPDATED on return.				;	
;									;
; Usage:	scrn_putca(char, attribute, &structure_name		;
;-----------------------------------------------------------------------;
_DATA	SEGMENT
scrn_putca_args STRUC			; args as pushed by calling program
	dw	0 			; saved bp value
	dw	0			; return address
pchar	dw	0			; char to write
pstruc	dw	0			; pointer to SCRN structure
scrn_putca_args ENDS
_DATA	ENDS

	PUBLIC	_scrn_putca	

_scrn_putca	PROC	NEAR
	push	bp			; set up frame pointer
	mov	bp,sp
	push	di
	mov	bx,[bp].pstruc		; get pointer to SCRN structure
	les	di,dword ptr[bx].off	; get offset in di, buffer addr in es
	mov	dx,[bx].port		; status port address
	mov	ch,byte ptr[bx].attrib	; get attribute into ch
	mov	cl,byte ptr[bp].pchar	;  and char into cl
	cmp	[bx].cgacrd, 0		; cga card present?
	jnz	cwait1			; yes...go wait
	mov	ax,cx			; no.
	stosw				; write it
	jmp	short cexit		; exit.

cwait1:
        in      al, dx                  ; wait for end of retrace
        shr     al, 1                   ; test horizontal trace bit
        jc      cwait1			; loop if still tracing
        cli                             ; disable writus interuptus
cwait2:
        in      al, dx                  ; now wait until the very moment
        shr     al, 1                   ; when the next retrace begins
        jnc     cwait2			; still waiting...
        mov     al,cl			; load the char into al for stosb
        stosb				; write it and update pointer
        sti                             ; enable interrupts again
cwait3:
        in      al, dx                  ; repeat these steps for the attribute
        shr     al, 1
        jc      cwait3
        cli                             
cwait4:
        in      al, dx                  
        shr     al, 1                   
	jnc     cwait4
        mov     al,ch			; load the attribute
        stosb
        sti				; whew...all done...enable interrupts
cexit:
	mov	[bx].off, di		; update logical cursor position
	pop	di			;  (offset) before leaving
	pop	bp
	ret	
_scrn_putca	ENDP


;-----------------------------------------------------------------------;
; _scrn_getca - get char and attrib from screen				;
;									;
; usage:	char = scrn_getca(&attrib,p_scn_data) 			;
;									;
;-----------------------------------------------------------------------;
_DATA	SEGMENT
getca_args STRUC		; input arguments
	dw	0		; saved BP value
	dw	0		; return address
gattrib	dw	0		; store attribute here 
gstruct	dw	0		; pointer to SCRN
getca_args ENDS
_DATA	ENDS

	PUBLIC	_scrn_getca

_scrn_getca	PROC	NEAR
	push	bp			; set up frame pointer
	mov	bp,sp		
	push	si
	
        mov	bx,[bp].gstruct		; get pointer to SCRN structure
	mov	dx,[bx].port		; get status port address
	push	ds			; lds uses ds - must save
	lds	si,dword ptr[bx].off	; get offset and segment address
gwait1:
        in      al, dx                  ; wait for end of retrace
        shr     al, 1                   ; test horizontal trace bit
        jc      gwait1			; loop if still tracing
        cli                             ; disable writus interuptus
gwait2:
        in      al, dx                  ; now wait until the very moment
        shr     al, 1                   ; when the next retrace begins
        jnc     gwait2			; still waiting...
        lodsb				; get the char into al
        sti                             ; enable interrupts again
	mov	cl,al			; save the char in cl
gwait3:
        in      al, dx                  ; repeat these steps for the attribute
        shr     al, 1
        jc      gwait3
        cli                             
gwait4:
        in      al, dx                  
        shr     al, 1                   
	jnc     gwait4
        lodsb				; get the attribute in al
        sti                             
	pop	ds			; restore data segment to norm
	mov	word ptr [bx],si 	; update offset (logical cursor)
	mov	si,word ptr[bp].gattrib	; get address to store attrib
        mov	byte ptr [si],al 	; store the attribute at "&attrib"
	mov	al,cl			; move the char to al and
	xor	ah,ah			;  zero out ah so that ax = char,
					;   the return value
	pop	si
	pop	bp
	ret
_scrn_getca	ENDP
		
_TEXT	ENDS

	END