;
; Fills a band across the screen with vertical bars in all 256
; attributes, then cycles a portion of the palette until a key is
; pressed.
;
; Assembled with TASM 4.0, linked with TLINK 6.10
; Checked by Jim Mischel 11/21/94
;
USE_BIOS equ	1  	;set to 1 to use BIOS functions to access the
			; DAC, 0 to read and write the DAC directly
GUARD_AGAINST_INTS equ 1 ;1 to turn off interrupts and set write index
			; before loading each DAC location, 0 to rely
			; on the DAC auto-incrementing
WAIT_VSYNC equ	1	;set to 1 to wait for the leading edge of
			; vertical sync before accessing the DAC, 0
			; not to wait
NOT_8088 equ	0	;set to 1 to use REP INSB and REP OUTSB when
			; accessing the  DAC directly, 0 to use
			; IN/STOSB and LODSB/OUT
CYCLE_SIZE 	equ	256	;# of DAC locations to cycle, 256 max
SCREEN_SEGMENT 	equ 	0a000h 	;mode 13h display memory segment
SCREEN_WIDTH_IN_BYTES equ 320 	;# of bytes across the screen in mode 13h
INPUT_STATUS_1 	equ 	03dah 	;input status 1 register port
DAC_READ_INDEX 	equ 	03c7h  	;DAC Read Index register
DAC_WRITE_INDEX 	equ 	03c8h 	;DAC Write Index register
DAC_DATA 	equ	03c9h	;DAC Data register

if NOT_8088
	.286
endif	;NOT_8088

	.model	small
	.stack	100h
	.data
;Storage for all 256 DAC locations, organized as one three-byte
; (actually three 6-bit values; upper two bits of each byte aren't
; significant) RGB triplet per color.
PaletteTemp	db	256*3 dup(?)
	.code
start:
	mov	ax,@data
	mov	ds,ax

;Select VGA's standard 256-color graphics mode, mode 13h.
	mov	ax,0013h	;AH = 0: set mode function,
	int	10h		; AL = 13h: mode # to set

;Read all 256 DAC locations into PaletteTemp (3 6-bit values, one
; each for red, green, and blue, per DAC location).

if WAIT_VSYNC
;Wait for the leading edge of the vertical sync pulse; this ensures
; that we read the DAC starting during the vertical non-display
; period.
	mov	dx,INPUT_STATUS_1
WaitNotVSync:			;wait to be out of vertical sync
	in	al,dx
	and	al,08h
	jnz	WaitNotVSync
WaitVSync:			;wait until vertical sync begins
	in	al,dx
	and	al,08h
	jz	WaitVSync
endif	;WAIT_VSYNC

if USE_BIOS
	mov	ax,1017h	;AH = 10h: set DAC function,
				; AL = 17h: read DAC block subfunction
	sub	bx,bx		;start with DAC location 0
	mov	cx,256		;read out all 256 locations
	mov	dx,seg PaletteTemp
	mov	es,dx
	mov	dx,offset PaletteTemp ;point ES:DX to array in which
				; the DAC values are to be stored
	int	10h		;read the DAC
else	;!USE_BIOS
 if GUARD_AGAINST_INTS
	mov	cx,CYCLE_SIZE	;# of DAC locations to load
	mov	di,seg PaletteTemp
	mov	es,di
	mov	di,offset PaletteTemp ;dump the DAC into this array
	sub	ah,ah		;start with DAC location 0
DACStoreLoop:
	mov	dx,DAC_READ_INDEX
	mov	al,ah
	cli
	out	dx,al		;set the DAC location #
	mov	dx,DAC_DATA
	in	al,dx		;get the red component
	stosb
	in	al,dx		;get the green component
	stosb
	in	al,dx		;get the blue component
	stosb
	sti
	inc	ah
	loop	DACStoreLoop
 else	;!GUARD_AGAINST_INTS
	mov	dx,DAC_READ_INDEX
	sub	al,al
	out	dx,al		;set the initial DAC location to 0
	mov	di,seg PaletteTemp
	mov	es,di
	mov	di,offset PaletteTemp ;dump the DAC into this array
	mov	dx,DAC_DATA
  if NOT_8088
	mov	cx,CYCLE_SIZE*3
	rep	insb		;read CYCLE_SIZE DAC locations at once
  else	;!NOT_8088
	mov	cx,CYCLE_SIZE	;# of DAC locations to load
DACStoreLoop:
	in	al,dx		;get the red component
	stosb
	in	al,dx		;get the green component
	stosb
	in	al,dx		;get the blue component
	stosb
	loop	DACStoreLoop
  endif	;NOT_8088
 endif	;GUARD_AGAINST_INTS
endif	;USE_BIOS

;Draw a series of 1-pixel-wide vertical bars across the screen in
; attributes 1 through 255.
	mov	ax,SCREEN_SEGMENT	
	mov	es,ax
	mov	di,50*SCREEN_WIDTH_IN_BYTES ;point ES:DI to the start
					    ; of line 50 on the screen
	cld
	mov	dx,100			;draw 100 lines high
RowLoop:
	mov	al,1			;start each line with attr 1
	mov	cx,SCREEN_WIDTH_IN_BYTES ;do a full line across
ColumnLoop:
	stosb				;draw a pixel
	add	al,1			;increment the attribute
	adc	al,0			;if the attribute just turned
					; over to 0, increment it to 1
					; because we're not going to
					; cycle DAC location 0, so
					; attribute 0 won't change
	loop	ColumnLoop
	dec	dx
	jnz	RowLoop

;Cycle the specified range of DAC locations until a key is pressed.
CycleLoop:
;Rotate colors 1-255 one position in the PaletteTemp array;
; location 0 is always left unchanged so that the background
; and border don't change.
	push	word ptr PaletteTemp+(1*3)	;set aside PaletteTemp
	push	word ptr PaletteTemp+(1*3)+2	; setting for attr 1
	mov	cx,254				
	mov	si,offset PaletteTemp+(2*3)
	mov	di,offset PaletteTemp+(1*3)
	mov	ax,ds
	mov	es,ax
	mov	cx,254*3/2
	rep	movsw			;rotate PaletteTemp settings
					; for attrs 2 through 255 to
					; attrs 1 through 254
	pop	bx			;get back original settings
	pop	ax			; for attribute 1 and move
	stosw				; them to the PaletteTemp
	mov	es:[di],bl		; location for attribute 255

if WAIT_VSYNC
;Wait for the leading edge of the vertical sync pulse; this ensures
; that we reload the DAC starting during the vertical non-display
; period.
	mov	dx,INPUT_STATUS_1
WaitNotVSync2:			;wait to be out of vertical sync
	in	al,dx
	and	al,08h
	jnz	WaitNotVSync2
WaitVSync2:			;wait until vertical sync begins
	in	al,dx
	and	al,08h
	jz	WaitVSync2
endif	;WAIT_VSYNC

if USE_BIOS
;Set the new, rotated palette.
	mov	ax,1012h	;AH = 10h: set DAC function,
				; AL = 12h: set DAC block subfunction
	sub	bx,bx		;start with DAC location 0
	mov	cx,CYCLE_SIZE	;# of DAC locations to set
	mov	dx,seg PaletteTemp
	mov	es,dx
	mov	dx,offset PaletteTemp ;point ES:DX to array from which
				; to load the DAC
	int	10h		;load the DAC
else	;!USE_BIOS
 if GUARD_AGAINST_INTS
	mov	cx,CYCLE_SIZE	;# of DAC locations to load
	mov	si,offset PaletteTemp ;load the DAC from this array
	sub	ah,ah		;start with DAC location 0
DACLoadLoop:
	mov	dx,DAC_WRITE_INDEX
	mov	al,ah
	cli
	out	dx,al		;set the DAC location #
	mov	dx,DAC_DATA
	lodsb
	out	dx,al		;set the red component
	lodsb
	out	dx,al		;set the green component
	lodsb
	out	dx,al		;set the blue component
	sti
	inc	ah
	loop	DACLoadLoop
 else	;!GUARD_AGAINST_INTS
	mov	dx,DAC_WRITE_INDEX
	sub	al,al
	out	dx,al		;set the initial DAC location to 0
	mov	si,offset PaletteTemp ;load the DAC from this array
	mov	dx,DAC_DATA
  if NOT_8088
	mov	cx,CYCLE_SIZE*3
	rep	outsb		;load CYCLE_SIZE DAC locations at once
  else	;!NOT_8088
	mov	cx,CYCLE_SIZE	;# of DAC locations to load
DACLoadLoop:
	lodsb
	out	dx,al		;set the red component
	lodsb
	out	dx,al		;set the green component
	lodsb
	out	dx,al		;set the blue component
	loop	DACLoadLoop
  endif	;NOT_8088
 endif	;GUARD_AGAINST_INTS
endif	;USE_BIOS

;See if a key has been pressed.
	mov	ah,0bh		;DOS check standard input status fn
	int	21h
	and	al,al		;is a key pending?
	jz	CycleLoop	;no, cycle some more

;Clear the keypress.
	mov	ah,1		;DOS keyboard input fn
	int	21h

;Restore text mode and done.
	mov	ax,0003h	;AH = 0: set mode function,
	int	10h		; AL = 03h: mode # to set
	mov	ah,4ch		;DOS terminate process fn
	int	21h

	end	start

