4 [EXTERN ___djgpp_base_address]
6 [GLOBAL _timer_get_fixed_seconds]
7 [GLOBAL _timer_get_fixed_secondsX]
8 [GLOBAL _timer_get_approx_seconds]
9 [GLOBAL _timer_set_rate]
10 [GLOBAL _timer_set_function]
11 [GLOBAL _timer_set_joyhandler]
37 td_in_timer equ TimerData
38 td_nested_counter equ td_in_timer+1
39 td__timer_cnt equ td_nested_counter+4
40 td_dos_timer equ td__timer_cnt+4
41 td_joystick_poller equ td_dos_timer+4
42 td_user_function equ td_joystick_poller+4
43 td_org_interrupt equ td_user_function+6
44 td_saved_stack equ td_org_interrupt+6
45 td_new_stack equ td_saved_stack+6
46 td_tick_count equ td_new_stack+6
47 td_Installed equ td_tick_count+4
48 td_TimerStack equ td_Installed+1
53 TIMER_LOCKED_CODE_START:
58 ; Return a 64-bit stamp that is the number of 1.19Mhz pulses
59 ; since the time was initialized. Returns in EDX:EAX.
60 ; Also, interrupts must be disabled.
62 xor eax, eax ; Clear all of EAX
63 out TCOMMAND, al ; Tell timer to latch
65 mov al, 0ah ; Find if interrupt pending
73 in al, TDATA ; Read in lo byte
75 in al, TDATA ; Read in hi byte
78 mov eax, [td__timer_cnt]
84 mov eax, [td_tick_count]
85 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
93 in al, TDATA ; Read in lo byte
95 in al, TDATA ; Read in hi byte
96 xchg ah, al ; arrange em correctly
97 mov edx, [td__timer_cnt]
98 sub dx, ax ; BX = timer ticks
103 mov eax, [td_tick_count]
104 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
112 _timer_get_fixed_seconds:
117 call timer_get_stamp64
120 ; Timing in fixed point (16.16) seconds.
121 ; Can be used for up to 1000 hours
122 shld edx, eax, 16 ; Keep 32+11 bits
124 ; edx:eax = number of 1.19Mhz pulses elapsed.
127 ; Make sure we won't divide overflow. Make time wrap at about 9 hours
129 sub edx, ebx ; subtract until negative...
130 jns sub_again ; ...to prevent divide overflow...
131 add edx, ebx ; ...then add in to get correct value.
133 ; eax = fixed point seconds elapsed...
141 _timer_get_fixed_secondsX:
145 call timer_get_stamp64
147 ; Timing in fixed point (16.16) seconds.
148 ; Can be used for up to 1000 hours
149 shld edx, eax, 16 ; Keep 32+11 bits
151 ; edx:eax = number of 1.19Mhz pulses elapsed.
155 sub edx, ebx ; subtract until negative...
156 jns xsub_again ; ...to prevent divide overflow...
157 add edx, ebx ; ...then add in to get correct value.
160 ; eax = fixed point seconds elapsed...
167 _timer_get_approx_seconds:
171 mov eax, [td_tick_count]
172 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
173 shld edx, eax, 16 ; Keep 32+16 bits, for conversion to fixed point
175 ; edx:eax = number of 1.19Mhz pulses elapsed.
179 sub edx, ebx ; subtract until negative...
180 jns approx_sub_again ; ...to prevent divide overflow...
181 add edx, ebx ; ...then add in to get correct value.
184 ; eax = fixed point seconds elapsed...
190 ;----------------------------------------------------------------------------
191 ;Prototype: extern void timer_set_rate(int count_val);
192 ;----------------------------------------------------------------------------
198 ; Make sure eax below or equal to 65535 and above 0
199 ; if its not, make it be 65536 which is normal dos
208 @@@: ; Set the timer rate to eax
210 mov dword [td_tick_count], 0
211 mov [td__timer_cnt], eax
212 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
213 out TCOMMAND, al ; Reset PIT channel 0
214 mov eax, [td__timer_cnt]
222 ;----------------------------------------------------------------------------
223 ;Prototype: extern void timer_set_function( void * function );
224 ;----------------------------------------------------------------------------
226 ; arg1 = near pointer to user function
228 mov eax, [esp+8] ; arg 1
230 mov dword [td_user_function+0], eax ; offset
231 mov word [td_user_function+4], cs ; selector
236 _timer_set_joyhandler:
239 mov dword [td_joystick_poller], eax
243 ;************************************************************************
244 ;************************************************************************
246 ;***** T I M E R _ H A N D L E R *****
248 ;************************************************************************
249 ;************************************************************************
256 mov ax, [cs:__my_ds] ; Interrupt, so point to our data segment
260 ; Increment time counter...
261 inc dword [td_tick_count]
263 mov eax, [td__timer_cnt]
264 add dword [td_dos_timer], eax ; Increment DOS timer
265 cmp dword [td_dos_timer], 65536
266 jb NoChainToOld ; See if we need to chain to DOS 18.2
267 and dword [td_dos_timer], 0ffffh
270 ; Call the original DOS handler....
273 call far dword [td_org_interrupt]
275 jmp NoReset ;old handler has reset, so we don't
279 mov al, 20h ; Reset interrupt controller
283 cmp byte [td_in_timer], 0
286 mov byte [td_in_timer], 1 ; Mark that we're in a timer interrupt...
288 ; Reenable interrupts
289 sti ; Reenable interrupts
291 cmp word [td_user_function+4], 0 ; Check the selector...
294 ; Switch stacks while calling the user-definable function...
298 mov dword [td_saved_stack+0], esp
299 mov word [td_saved_stack+4], ss
300 lss esp, [td_new_stack] ; Switch to new stack
301 call far dword [td_user_function] ; Call new function
302 lss esp, [td_saved_stack] ; Switch back to original stack
308 cmp dword [td_joystick_poller], 0
310 mov eax, [td__timer_cnt]
311 mov dword [td_saved_stack+0], esp
312 mov word [td_saved_stack+4], ss
313 lss esp, [td_new_stack] ; Switch to new stack
316 call dword [td_joystick_poller]
319 lss esp, [td_saved_stack] ; Switch back to original stack
323 mov byte [td_in_timer], 0
326 ;;mov al, 20h ; Reset interrupt controller
331 iretd ; Return from timer interrupt
333 TIMER_LOCKED_CODE_STOP:
335 ;************************************************************************
336 ;************************************************************************
338 ;***** T I M E R _ I N I T *****
340 ;************************************************************************
341 ;************************************************************************
348 cmp byte [td_Installed], 1
349 je NEAR AlreadyInstalled
353 mov dword [td__timer_cnt], 65536 ; Set to BIOS's normal 18.2 Hz
354 mov dword [td_dos_timer], 0 ; clear DOS Interrupt counter
355 mov dword [td_user_function+0], 0 ; offset of user function
356 mov word [td_user_function+4], 0 ; selector of user function
358 lea eax, [ds:td_TimerStack] ; Use EAX as temp stack pointer
359 add eax, STACK_SIZE ; Top of stack minus space for saving old ss:esp
360 mov dword [td_new_stack+0], eax
361 mov word [td_new_stack+4], ds
363 ;--------------- lock data used in interrupt
364 mov eax, (td_TimerStack-TimerData)+STACK_SIZE ;sizeof timer_data
368 and edi, 0ffffh ; si:di = length of region to lock in bytes
370 add ebx, [___djgpp_base_address]
373 and ecx, 0ffffh ; bx:cx = start of linear address to lock
374 mov eax, 0600h ; DPMI lock address function
377 int 3 ; LOCK FAILED!!
379 ;--------------- lock code used in interrupt
380 mov eax, TIMER_LOCKED_CODE_STOP
381 sub eax, TIMER_LOCKED_CODE_START
382 inc eax ; EAX = size of timer interrupt handler
386 and edi, 0ffffh ; si:di = length of region to lock in bytes
387 mov ebx, TIMER_LOCKED_CODE_START
388 add ebx, [___djgpp_base_address]
391 and ecx, 0ffffh ; bx:cx = start of linear address to lock
392 mov eax, 0600h ; DPMI lock address function
394 jnc @@@@@ ;This is getting fun
395 int 3 ; LOCK FAILED!!
398 ;**************************************************************
399 ;******************* SAVE OLD INT8 HANDLER ********************
400 ;**************************************************************
404 mov dword [td_org_interrupt+0],edx
405 mov word [td_org_interrupt+4],cx
407 ;**************************************************************
408 ;***************** INSTALL NEW INT8 HANDLER *******************
409 ;**************************************************************
413 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
414 out TCOMMAND, al ; Reset PIT channel 0
415 mov eax, [td__timer_cnt]
420 mov dword [td_tick_count], 0
421 mov byte [td_Installed],1
425 mov edx,timer_handler
431 push dword _timer_close
443 ;************************************************************************
444 ;************************************************************************
446 ;***** T I M E R _ C L O S E _ *****
448 ;************************************************************************
449 ;************************************************************************
457 cmp byte [td_Installed], 0
459 mov byte [td_Installed], 0
461 ;**************************************************************
462 ;***************** RESTORE OLD INT8 HANDLER *******************
463 ;**************************************************************
466 mov al, 36h ; count in binary, mode 3, load low byte then hi byte, counter 0: 00 11 011 0
467 out TCOMMAND, al ; Reser PIT channel 0
475 mov edx,dword [td_org_interrupt+0]
476 mov cx,word [td_org_interrupt+4]
481 cmp dword [td_nested_counter], 0
482 je NoNestedInterrupts
483 mov eax, [td_nested_counter]