		title		-  Animated "o" system program

vectors 	segment at 0
		ORG	8h*4
timer	label	dword
		ORG	16h*4
kbio	label	dword
vectors 	ends

cseg		segment para
		assume	cs:cseg
		org	100h

begin:		jmp	init_vectors		; go initialize vectors


;-------------------------------;
;				;
;  data area for this program	;
;				;
;-------------------------------;

old_timer	dd	?	; Old timer interrupt location
old_kbio	dd	?	; Old keyboard I/O interrupt location
timer_tick	db	0	; set if timer ticked
in_kbio		db	0
which		db	0	; selector in "o_table"
csize		db	10h	; size of character in bytes in "o_table"
enabled		db	1	; spinning "o"s enabled flag
shift_ticks	db	0
o_table:			; font table of spinning "o"s
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00110000b
	db	01100000b
	db	11100000b
	db	11010110b
	db	11001110b
	db	01101100b
	db	00111000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00111000b
	db	01101100b
	db	11010000b
	db	11010000b
	db	11010000b
	db	01101100b
	db	00111000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00111000b
	db	01101100b
	db	11001110b
	db	11010110b
	db	11100000b
	db	01100000b
	db	00110000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00111000b
	db	01101100b
	db	11000110b
	db	11111110b
	db	11000110b
	db	01000100b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00111000b
	db	01101100b
	db	11100110b
	db	11010110b
	db	00001110b
	db	00001100b
	db	00011000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00111000b
	db	01101100b
	db	00010110b
	db	00010110b
	db	00010110b
	db	01101100b
	db	00111000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00011000b
	db	00001100b
	db	00001110b
	db	11010110b
	db	11100110b
	db	01101100b
	db	00111000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	01000100b
	db	11000110b
	db	11111110b
	db	11000110b
	db	01101100b
	db	00111000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00111000b
	db	01101100b
	db	11000110b
	db	11000110b
	db	11000110b
	db	01101100b
	db	00111000b
	db	00000000b
	db	00000000b
	db	00000000b
	db	00000000b

; The keyboard I/O interrupt intercept routine follows.
intercept	proc	far
		cli
		nop
		pushf
		cmp	timer_tick,0	; wait 1/18 of a second before font update
		je	dont_do_this
		cmp	in_kbio,1	; make sure we don't overflow any stacks
		ja	dont_do_this
		cmp	ah,1		; only update font on keyboard poll
		je	do_this
		cmp	ah,11h		; extended keyboard poll
		je	do_this
dont_do_this:
		jmp	go_kbio1
do_this:
		mov	timer_tick,0
		inc	in_kbio
		push	es
		push	ds
		push	si
		push	di
		push	bp
		push	ax
		push	bx
		push	cx
		push	dx

		mov	ax,040h
		mov	es,ax		; load BIOS data segment

		mov	bh,es:[85h]	; Character height
		cmp	bh,14
		jb	close_jmp
		cmp	bh,16
		ja	close_jmp
		mov	al,es:[49h]	; Video mode
		cmp	al,3
		je	mode_ok
close_jmp:
		jmp	go_kbio
mode_ok:
		cmp	in_kbio,1
		jne	still_counting

		mov	al,es:[17h]	; Get keyboard flags
		and	al,3
		cmp	al,3
		jne	shifts_not_down
		inc	shift_ticks	; both shift keys are down
		cmp	shift_ticks,18
		jne	still_counting
		xor	enabled,1	; toggle enabled status
		jmp	enabled_status_changed
shifts_not_down:
		mov	shift_ticks,0
still_counting:
		cmp	enabled,0
		je	go_kbio
enabled_status_changed:
		mov	dx,es:[63h]	; video controller base address
		add	dl,6		; address of status register
updating:
		nop
		nop
		cli
		nop
		in	al,dx		; get vertical retrace status
		test	al,8
		jnz	now		; jump if in vertical retrace
		sti			; temporarily enable interrupts
		jmp	updating
now:
		cmp	enabled,0
		je	load_orig	; jump to load a plain, unbroken "o"
		mov	al,which	; get which "o" to load
		inc	al
		and	al,7		; 8 possible "o"s to load
		mov	which,al
		jmp	load_next_o
load_orig:
		mov	al,8
load_next_o:
		mul	csize		; make index into "o_table"
		mov	bp,offset o_table
		add	bp,ax
		mov	ax,cs
		mov	es,ax
		mov	ax,01100h	; do interrupt to load character font
		mov	bl,0		; table number
					; bh = number of bytes per character
		mov	cx,1		; number of characters to load
		mov	dx,06fh		; ASCII value of "o"
		int	10h
go_kbio:
		pop	dx
		pop	cx
		pop	bx
		pop	ax
		pop	bp
		pop	di
		pop	si
		pop	ds
		pop	es
		dec	in_kbio
go_kbio1:
		popf
		jmp	old_kbio
intercept 	endp

; The new timer interrupt routine follows.
new_timer	proc	far
		mov	timer_tick,1
		jmp	old_timer
new_timer	endp

; Do TSR initialization.
init_vectors	proc	near
		assume	ds:vectors
		mov	ax,vectors
		mov	ds,ax

		cli
; Load timer interrupt vector.
		mov	ax,word ptr timer
		mov	word ptr old_timer,ax
		mov	ax,word ptr timer[2]
		mov	word ptr old_timer[2],ax
		mov	ax, offset new_timer
		mov	word ptr timer,ax
		mov	word ptr timer[2],cs

; Load keyboard I/O interrupt vector.
		mov	ax,word ptr kbio
		mov	word ptr old_kbio,ax
		mov	ax,word ptr kbio[2]
		mov	word ptr old_kbio[2],ax
		mov	ax, offset intercept
		mov	word ptr kbio,ax
		mov	word ptr kbio[2],cs
		sti

		mov	es,cs:[02ch]		; release environment
		mov	ah,49h
		int	21h

		mov	dx,offset init_vectors	; end of resident portion
		int	27h			; terminate but stay resident
init_vectors	endp

cseg	       ends

		END	begin
