.model tiny
.code 

TIMER	equ 	040h   		; 8254 TIMER - BASE ADDRESS
PORT_B	equ	061h		; PORT B READ/WRITE DIAGNOSTIC REGISTER
GATE2	equ	00000001b	; TIMER 2 INPUT CATE CLOCK BIT
SPK2	equ	00000010b	; SPEAKER OUTPUT DATA ENABLE BIT

.startup 

rebeep:
	mov 	cx, 1331 	; divisor for 896 hz tone
	mov 	bl, 31		; set count for 31/64 second for beep

	;****
beep:
	; 10/12/2013 (3584/2048)
	; 07/12/2013 (sti)
	; 03/12/2013
	;
	; TEST4.ASM - 06/10/85  POST AND BIOS UTILITY ROUTINES
	;
	; ROUTINE TO SOUND THE BEEPER USING TIMER 2 FOR TONE
	;
	; ENTRY:
	;    (BL) = DURATION COUNTER ( 1 FOR 1/64 SECOND )
	;    (CX) = FREQUENCY DIVISOR (1193180/FREQUENCY) (1331 FOR 886 HZ)
	; EXIT:				:
	;    (AX),(BL),(CX) MODIFIED.

	;pushf			; save interrupt status
	cli			; block interrupts during update
	mov	al, 10110110b	; select timer 2, lsb, msb binary
	out	TIMER+3, al 	; write timer mode register
	jmp	$+2		; I/O delay
	mov	al, cl		; divisor for hz (low)
	out	TIMER+2,AL	; write timer 2 count - lsb
	jmp	$+2		; I/O delay
	mov	al, ch		; divisor for hz (high)
	out	TIMER+2, al	; write timer 2 count - msb
	in	al, PORT_B	; get current setting of port
	mov	ah, al		; save that setting
	or	al, GATE2+SPK2	; gate timer 2 and turn speaker on
	out	PORT_B, al	; and restore interrupt status
	;popf
	sti
@@:				; 1/64 second per count (bl)
	;mov	cx, 1035	; delay count for 1164 of a second	
	mov	cx, 3584
	call	waitf		; go to beep delay 1/64 count
	dec	bl		; (bl) length count expired?
	jnz	short @b	; no - continue beeping speaker
	;
	;pushf			; save interrupt status
	cli			; block interrupts during update
	in	al, PORT_B	; get current port value
	or	al, not (GATE2+SPK2) ; isolate current speaker bits in case
	and	ah, al		; someone turned them off during beep
	mov	al, ah		; recover value of port
	or	al, not (GATE2+SPK2) ; force speaker data off
	out	PORT_B, al	; and stop speaker timer
	;popf			; restore interrupt flag state
	sti
	;mov	cx, 1035	; force 1/64 second delay (short)
	mov	cx, 2048
	call	waitf		; minimum delay between all beeps
	;pushf			; save interrupt status
	cli			; block interrupts during update
	in	al, PORT_B	; get current port value in case	
	and	al, GATE2+SPK2	; someone turned them on
	or	al, ah		; recover value of port_b
	out	PORT_B, al	; restore speaker status
	;popf			; restore interrupt flag state
	
	sti

	xor 	ah, ah
	int 	16h

	cmp 	al, 1Bh
	jne	short rebeep


	mov ax, 1  ; exit
	int 20h	   ; sys _exit

REFRESH_BIT equ	00010000b 	; REFRESH TEST BIT

waitf:
	; 03/12/2013
	;
	; TEST4.ASM - 06/10/85  POST AND BIOS UTILITY ROUTINES
	;
	; WAITF - FIXED TIME WAIT ROUTINE HARDWARE CONTROLLED - NOT PROCESSOR	
	;
	; ENTRY:
	;    (CX) = COUNT OF 15.,085737 MICROSECOND INTERVALS TO WAIT
	;	    MEMORY REFRESH TIMER 1 OUTPUT USED AS REFERENCE
	; EXIT:	
	;	    AFTER (CX) TIME COUNT (PLUS OR MINUS 16 MICROSECONDS)
	;    (CX) = 0

	; delay for (cx)*15.085737 us
	push ax			; save work register (ah)	
@@:
				; use timer 1 output bits
	in	al, PORT_B	; read current counter output status
	and	al, REFRESH_BIT	; mask for refresh determine bit
	cmp	al, ah		; did it just change
	je	short @b	; wait for a change in output line
	;
	mov	ah, al		; save new lflag state
	loop	@b		; decrement half cycles till count end		
	;
	pop	ax		; restore (ah)
	retn	
	
 .exit

end
