[comp.sys.ibm.pc] EGA Scrolling

schmitz@uiucdcsb.UUCP (06/08/87)

I'm trying to implement hardware scrolling on a Paradise EGA card.  By
hardware scrolling I mean that the screen should "scroll" just by changing
the Start Address High and Start Adress Low registers of the CRT controller
chip.  The problem is that  don't know how to make the wraparound at the
end of the video buffer function properly.  When I leave the memory
address generator in word mode, after the high bit becomes 1, it
apparently starts accessing odd locations in bit plane 0.  That's fine
except when the processor access the video buffer in odd/even mode it
writes the charater byte to an even location in bit plane 0, and the
attribute byte to the corresponding location in bit plane 1.  There is
no way to fill in the odd addresses in bit plane 0.  These odd addresses
will be accessed by the memory address generator when it is looking for
characters to write and the high bit in the memory address register is 1.
The result is you get sixteen screenfuls (or so) of text, and then 
sixteen blank screenfuls until the wraparound.  I'm using a 64K buffer
because the memory address register is a sixteen bits wide, so you need
that big a buffer to get the wraparound.  For some perverse reason, I
put it at A000.  I do have a solution which works by changing to byte
mode.  But it is horribly inefficent!  First you enable bit plane zero
and write the ascii code.  Then you enable bit plane 1 and write the
attribute byte.  This must be done for every character written.  
	I would like to find a solution that will keep the processor
mapping in odd/even mode so that the character and the attribute byte
can be written with a single write.  
	Below is a program that demonstrates the "bytewise" solution.
It fills the video buffer with hexadecimal numbers.  Each number has
a value which is its offset from the start of the video buffer.  That
way you can always tell where you are in the buffer.  When the program
is running 'j' and 'k' scroll up and down by lines, and ' ' and '-'
scroll up and down by screenfuls.  Note that there are 32 screenfuls!
	I would be most grateful for help with this problem.

+=============================================================================+
|	Michael Schmitz University of Illinois	 Dept. of CS (217) 333-6680   |
|									      |
|       arpa		schmitz@b.cs.uiuc.edu                    	      |
|       csnet		schmitz@uiuc.csnet				      |
|       usenet		ihnp4!uiucdcs!schmitz				      |
+=============================================================================+


;===============================================================================
;				   VID.ASM
;===============================================================================

.RADIX 16

INCLUDE	vid.mac

sseg segment stack
	db 256 dup(?)
sseg	ends

dseg	segment				; the data segment is not used
tmp	dw ?
dseg	ends

vid_buf segment at 0A000 		; segment extends for 64K bytes
vid_buf ends

cseg segment
	assume cs:cseg, ds:dseg,es:vid_buf
main	proc far
	push ds
	sub ax,ax
	push ax
	mov ax,vid_buf
	mov es,ax	
	mov ax,dseg
	mov ds,ax
	mov bx,0

	G_misc 4
	
	G_mode 0

	C_mode 0E3
	
	S_mode 7

	; S_mode 7 means that odd/even writes by the processor is
	; disabled.  The processor must call S_map to change the default
	; write bit plane to 0 or 1.  Bytes containing ascii values go
	; to bit plane 0, while the corresponding attribute bytes go to
	; bit plane 1. There must be a way to have this done
	; automatically, without ruining the wraparound.

	mov cx, 2000
fill:	mov al, 40
	call pr_bx
	add bx, 4
	mov al,60
	call pr_bx
	add bx,4
	loop fill

scroll:	mov ah, 7
	int 21
	cmp al, ' '
	je scr_up
	cmp al, '-'
	je scr_dn
	cmp al, 'j'
	je ln_dn
	cmp al, 'k'
	je ln_up

	; Only possibility left is to exit, after restoring all
	; modified EGA registers to their original values.

	G_misc 0E
	G_mode 10
	C_mode 0A3
	C_sa 0, 0
	S_mode 03
	S_map 2

	ret
scr_up:	add bx,780
	jmp ld_ega
scr_dn:	sub bx,780
	jmp ld_ega
ln_up:	add bx,50
	jmp ld_ega
ln_dn:	sub bx,50
ld_ega:	C_sa bl, bh
	jmp scroll
main	endp
	
pr_bx	proc	near

; The value in bx is interpreted as four hexadecimal characters and then
; these characters are written to the regen buffer starting at location
; es:[bx].  Thus each word in the regen buffer gives its offset from the
; beginning of the regen buffer.  The attribute byte to use is in al.
; All registers are preserved.

	push 	ax
	push	si
	push	cx
	push	dx
	mov 	dx, ax
	mov 	cx, 0C
	mov	si, 0
n_chr:	mov	ax, 0F
	shl	ax, cl
	and 	ax, bx
	shr	ax, cl
	cmp	al, 9
	ja	lttr
	add	al, 30
	jmp	prnt
lttr:	add	al, 37
prnt:	mov	ah, dl

	; The next four lines are the part that really need improvement.
	; Only a byte can be written at a time, and in between those two
	; writes the bit planes have to be changed.  However, when I
	; change to odd/even mapping of processor accesses into the
	; regen buffer, I can't fix things up to get scrolling to
	; wraparound the end of the regen buffer.

	S_map	0
	mov	es:[bx + si], al
	S_map	1
	mov	es:[bx + si], ah
	inc	si
	sub	cx, 4
	cmp	cx, 0
	jge	n_chr
	pop	dx
	pop	cx
	pop	si
	pop	ax
	ret
pr_bx	endp
cseg	ends
	end main



;===============================================================================
;				    VID.MAC
;===============================================================================

C_sa	MACRO	low, high

	;; set the start address high and start address low of the
	;; CRTC chip

	push	dx
	push	ax
	mov 	dx, 3d4H
	mov 	al, 0dH
	mov 	ah, &low
	out	dx, ax
	mov 	al, 0cH
	mov 	ah, &high
	out 	dx, ax
	pop	ax
	pop	dx
	ENDM
	
G_misc	MACRO	pattern

	;; Among other things the graphics miscellanous register controls the
	;; chaining of odd maps to even, and the mapping of the regen buffer
	;; into processor address space.  The default is 0EH.

	push 	dx
	push	ax
	mov 	ah, &pattern
	mov 	al, 06H
	mov	dx, 3ceH
	out	dx, ax
	pop	ax
	pop	dx
	ENDM

G_mode	MACRO	pattern

	;; Again, this has something to do with the chaining of odd maps
	;; to even.  Bit 4 of this register should be the same as memory
	;; mode register bit 3 of the sequencer. The default value is 10H.

	push 	dx
	push	ax
	mov 	ah, &pattern
	mov 	al, 05H
	mov	dx, 3ceH
	out	dx, ax
	pop	ax
	pop	dx
	ENDM

C_mode	MACRO	pattern

	;; This is the mode control register of the CRTC chip.  The default
	;; value is A3H.
	
	push 	dx
	push	ax
	mov 	ah, &pattern
	mov 	al, 17H
	mov 	dx, 3d4H
	out	dx, ax
	pop	ax
	pop	dx
	ENDM

S_mode	MACRO	pattern

	;; This is the mode control register of the Sequencer chip.  The 
	;; default value is 03H.
	
	push 	dx
	push	ax
	mov 	ah, &pattern
	mov 	al, 04H
	mov 	dx, 3c4H
	out	dx, ax
	pop	ax
	pop	dx
	ENDM

S_map	MACRO plane

	;; plane is 0 or 1.  

	push	dx
	push	ax
	mov	ah, &plane
	add	ah, 1
	mov	al, 02H
	mov 	dx, 3c4H
	out	dx, ax
	pop	ax
	pop	dx
	ENDM