Path: utzoo!attcan!uunet!cs.utexas.edu!usc!apple!portal!cup.portal.com!ekalenda From: ekalenda@cup.portal.com (Edward John Kalenda) Newsgroups: comp.os.msdos.programmer Subject: Re: System timer reprogramming Message-ID: <33855@cup.portal.com> Date: 13 Sep 90 06:25:44 GMT References: <20232@orstcs.CS.ORST.EDU> Organization: The Portal System (TM) Lines: 222 Dave Denson (densond@prism.cs.orst.edu) writes: > I need to find out how to reprogram the IBM clock-tick timer to a faster > rate. Norton's Programming Guide gives little or no information on this. > I plan to use int 08h to decrement a one-byte timer for game clocking > purposes. I've excerpted the following from a MSC6.0 small model program I did which should do what you want. Ed ekalenda@cup.portal.com ------- clip here -------------- TITLE timer.asm NAME timer _TEXT SEGMENT WORD PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT WORD PUBLIC 'DATA' _DATA ENDS ASSUME CS: _TEXT, DS: _DATA _DATA SEGMENT ; local stack for the timer interrupt handler timer_stack db 128 dup(0) timer_stack_start dw 8 dup(0) rate dw 0 ; current tick rate pass_int dw 0 ; used to pass int to old handler active dw 0 public _timer_count ; in C, declare as: _timer_count dd 0 ; extern unsigned long timer_count _DATA ENDS _TEXT SEGMENT ; ================================================== _timer_start =========== PUBLIC _timer_start _timer_start proc near ; save all registers used push ax push bx push dx push es ; check for already being active cmp _timer_active,0 jne already_active ; initialize the counter mov word ptr _timer_count,0 mov word ptr _timer_count+2,0 ; take over the timer interrupt mov ax,3508h ; get interrupt vector int 21h mov word ptr cs:old_int08h,bx mov word ptr cs:old_int08h+2,es mov dx,offset _timer_handler push ds push cs pop ds mov ax,2508h ; set interrupt handler int 21h pop ds ; reprogram the timer frequency pushf cli mov al,34h out 43h,al mov ax,0800h ; 32 times regular rate out 40h,al mov al,ah out 40h,al mov pass_int,0 mov _timer_active,1 popf ; restore registers used already_active: pop es pop dx pop bx pop ax ret _timer_start ENDP ; ================================================== _timer_stop ============ PUBLIC _timer_stop _timer_stop proc near ; save all registers used push ax push dx push es ; check for timer not being active cmp _timer_active,0 je not_active ; restore the timer frequency pushf cli mov al,34h out 43h,al mov al,0 ; 0 means 65536 out 40h,al out 40h,al mov _timer_active,0 ; restore the timer interrupt, do not use int21 as control-C will interrupt ; this operation causing the timer handler to not be restored push ds lds dx,cs:old_int08h mov ax,0 mov es,ax mov es:[20h],dx mov es:[22h],ds pop ds popf ; restore registers not_active: pop es pop dx pop ax ret _timer_stop endp ; ================================================== _timer_handler =========== ; in code segment to allow stack switch before saving registers old_sp dw ? old_ss dw ? new_sp dw offset timer_stack_start new_ss dw seg timer_stack_start our_ds dw _DATA ; in code segment to allow chain to old handler after restoring environment ; to that existing at the interrupt old_int08h dd 0 ; old handler address _timer_handler proc far ; switch to a local stack mov cs:old_ss,ss mov cs:old_sp,sp mov ss,cs:new_ss mov sp,cs:new_sp ; save the registers used push ax push dx push si push ds push es ; point to our data area mov ds,cs:our_ds ; see if we are active yet cmp _timer_active,0 jne do_stuff jmp do_pass_int ; do our thing here, maintain a count of number of interrupts seen do_stuff: add word ptr _timer_count,1 adc word ptr _timer_count+2,0 ; fall through to here, see if we pass control to the old handler test_pass_int: mov ax,0800h add pass_int,ax jnc do_not_pass_int ; restore the registers and the stack, then execute the real int08h handler do_pass_int: pop es pop ds pop si pop dx pop ax mov ss,cs:old_ss mov sp,cs:old_sp jmp cs:[old_int08h] do_not_pass_int: ; dismiss the interrupt and restore registers mov al,20h out 20h,al pop es pop ds pop si pop dx pop ax mov ss,cs:old_ss mov sp,cs:old_sp iret _timer_handler endp _TEXT ENDS END