	Title Timer routines for ApBasic
	Page 60,130
;	Created 10-5-1987 k. murray
;
Cseg	Segment byte public 'Code'
	Assume Cs:Cseg,Ds:nothing,Es:nothing
Start:
	Jmp	Timer_On	; Turn timer on
	Jmp	Timer_Off	; Turn timer off and reset INT
	Jmp	Timer_Reset	; Reset timer counter to zero
;
; Some data locations
Old_Int1c Dw	0,0		; Place to hold old Int 1ch
TrapMask  Dw	0,0		; mask to set trap word for our user number
UserTicks Dw	0		; User supplied number of ticks
TotalTicks Dw	0		; Counter Dec by interrupt routine
ProgDs	Dw	0		; Program's Data segment for int routine
;
;	SUB Timer.Reset
;
Timer_Reset Proc Far
	Mov	Ax,Cs:UserTicks
	Mov	Cs:TotalTicks,Ax	; Reset counter
	Ret
Timer_Reset Endp
;
;	SUB Timer.Off
;
Timer_Off Proc Far
	Mov	Ax,251ch
	Push	Ds
	Lds	Dx,dword ptr Old_Int1c	; get adr. of vector in Ds:Dx
	Int	21h			; set old int back
	Pop	Ds
	Ret
Timer_Off Endp
;
;	SUB Timer.On Ticks%,Userno%
;	Stack Frame:
;	+8	Ticks% adr.
;	+6	Userno% adr.
;	+4	Return Segment
;	+2	Return offset
;	+0	Saved Bp
;
Timer_On Proc Far
	Push	Bp
	Mov	Bp,Sp
		; generate a trap mask from the Userno% variable
	Mov	Bx,[Bp+6]		; Get user number adr.
	Mov	Cx,[Bx]			; Get user number
	Dec	Cx			; make relative to zero
	Cmp	Cx,32
	Jb	Timer_On2
	Mov	Cx,32			; use smallest
Timer_On2:
	Xor	Ax,Ax
	Mov	Dx,Ax
	Inc	Ax			; set low bit
	Clc				; clear carry
	Jcxz	Timer_On6
Timer_On4:
	Rcl	Ax,1
	Rcl	Dx,1			; shift dword over one bit
	Loop	Timer_On4
Timer_On6:
	Mov	Cs:TrapMask,Ax
	Mov	Cs:TrapMask+2,Dx	; save mask
		; Save the Ticks% variable
	Mov	Bx,[Bp+8]		; Get Ticks% adr.
	Mov	Ax,[Bx]			; get Ticks%
	Mov	Cs:UserTicks,Ax		; save user ticks
		; Setup for doing the Interrupt
	Push	Es
	Push	Ds
	Mov	Ax,351ch
	Int	21h			; Get old Int1c vector
	Mov	Cs:Old_Int1c,Bx
	Mov	Cs:Old_Int1c+2,Es	; save it
	Push	Cs
	Pop	Ds
	Mov	Dx,Offset Timer_Int	; Adr. of timer routine in Ds:Dx
	Mov	Ax,251ch
	Int	21h			; Set new Int1c vector
	Pop	Ds
	Pop	Es
		; set initial timer value
	Mov	Ax,Cs:UserTicks
	Mov	Cs:TotalTicks,Ax	; Reset counter
	Mov	Cs:ProgDs,Ds		; save current data segment
		; Clean up the parameters and return
	Pop	Bp
	Ret	4	; Two parameters at 2 bytes/param
Timer_On Endp
;
;
;	Timer interrupt routine. This routine is called by Int 1ch.
;	When the TotalTicks variable is zero, then this routine set's
;	the user bit defined in Timer_On.
Timer_Int:
	Push	Ax
	Push	Dx
	Push	Ds			; save some registers
;
	Push	Cs
	Pop	Ds			; Ds=Cs
	Dec	word ptr TotalTicks	; Dec counter
	Jnz	Timer_Int2		; not zero yet

		; User TrapMask to set trap bit in trap dword in base page
	Mov	Ax,UserTicks
	Mov	TotalTicks,Ax		; Restore counter
	Mov	Ax,TrapMask
	Mov	Dx,TrapMask+2
	Push	word ptr ProgDs
	Pop	Ds
	Or	word ptr Ds:[0],Ax
	Or	word ptr Ds:[2],Dx	; set timer bit in trap dword
Timer_Int2:
;
	Pop	Ds
	Pop	Dx
	Pop	Ax		; Restore the registers
	Iret
Cseg	Ends
	End	Start
