; Program that draws a diagonal line to illustrate the use of a
; Color Don't Care register setting of 0FFH to support fast
; read-modify-write operations to VGA memory in write mode 3 by
; drawing a diagonal line.
;
; Note: Works on VGAs only.
;
; By Michael Abrash
;
stack	segment word stack 'STACK'
	db	512 dup (?)
stack	ends
;
VGA_SEGMENT	 EQU	0a000h
SCREEN_WIDTH	 EQU	80	;in bytes
GC_INDEX	 EQU	3ceh	;Graphics Controller Index register
SET_RESET	 EQU	0	;Set/Reset register index in GC
ENABLE_SET_RESET EQU	1	;Enable Set/Reset register index in GC
GRAPHICS_MODE	 EQU	5	;Graphics Mode register index in GC
COLOR_DONT_CARE	 EQU	7	;Color Don't Care register index in GC
;
code	segment word 'CODE'
	assume	cs:code
Start	proc	near
;
; Select graphics mode 12h.
;
	mov	ax,12h
	int	10h
;
; Select write mode 3 and read mode 1.
;
	mov	dx,GC_INDEX
	mov	al,GRAPHICS_MODE
	out	dx,al
	inc	dx
	in	al,dx		;VGA registers are readable, bless them!
	or	al,00001011b	;bit 3=1 selects read mode 1, and
				; bits 1 & 0=11 selects write mode 3
	jmp	$+2		;delay between IN and OUT to same port
	out	dx,al
	dec	dx
;
; Set up set/reset to always draw in white.
;
	mov	al,SET_RESET
	out	dx,al
	inc	dx
	mov	al,0fh
	out	dx,al
	dec	dx
	mov	al,ENABLE_SET_RESET
	out	dx,al
	inc	dx
	mov	al,0fh
	out	dx,al
	dec	dx
;
; Set Color Don't Care to 0, so reads of VGA memory always return 0FFH.
;
	mov	al,COLOR_DONT_CARE
	out	dx,al
	inc	dx
	sub	al,al
	out	dx,al
;
; Set up the initial memory pointer and pixel mask.
;
	mov	ax,VGA_SEGMENT
	mov	ds,ax
	sub	bx,bx
	mov	al,80h
;
; Draw 400 points on a diagonal line sloping down and to the right.
;
	mov	cx,400
DrawDiagonalLoop:
	and	[bx],al		;reads display memory, loading the latches,
				; then writes AL to the VGA. AL becomes the
				; bit mask, and set/reset provides the
				; actual data written
	add	bx,SCREEN_WIDTH
				; point to the next scan line
	ror	al,1		;move the pixel mask one pixel to the right
	adc	bx,0		;advance to the next byte if the pixel mask wrapped
	loop	DrawDiagonalLoop
;
; Wait for a key to be pressed to end, then return to text mode and
; return to DOS.
;
WaitKeyLoop:
	mov	ah,1
	int	16h
	jz	WaitKeyLoop
	sub	ah,ah
	int	16h		;clear the key
	mov	ax,3
	int	10h		;return to text mode
	mov	ah,4ch
	int	21h		;done
Start	endp
code	ends
	end	Start
