12 [EXTERN ___djgpp_base_address]
14 [GLOBAL _timer_get_fixed_seconds]
15 [GLOBAL _timer_get_fixed_secondsX]
16 [GLOBAL _timer_get_approx_seconds]
17 [GLOBAL _timer_set_rate]
18 [GLOBAL _timer_set_function]
19 [GLOBAL _timer_set_joyhandler]
45 td_in_timer equ TimerData
46 td_nested_counter equ td_in_timer+1
47 td__timer_cnt equ td_nested_counter+4
48 td_dos_timer equ td__timer_cnt+4
49 td_joystick_poller equ td_dos_timer+4
50 td_user_function equ td_joystick_poller+4
51 td_org_interrupt equ td_user_function+6
52 td_saved_stack equ td_org_interrupt+6
53 td_new_stack equ td_saved_stack+6
54 td_tick_count equ td_new_stack+6
55 td_Installed equ td_tick_count+4
56 td_TimerStack equ td_Installed+1
61 TIMER_LOCKED_CODE_START:
66 ; Return a 64-bit stamp that is the number of 1.19Mhz pulses
67 ; since the time was initialized. Returns in EDX:EAX.
68 ; Also, interrupts must be disabled.
70 xor eax, eax ; Clear all of EAX
71 out TCOMMAND, al ; Tell timer to latch
73 mov al, 0ah ; Find if interrupt pending
81 in al, TDATA ; Read in lo byte
83 in al, TDATA ; Read in hi byte
86 mov eax, [td__timer_cnt]
92 mov eax, [td_tick_count]
93 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
101 in al, TDATA ; Read in lo byte
103 in al, TDATA ; Read in hi byte
104 xchg ah, al ; arrange em correctly
105 mov edx, [td__timer_cnt]
106 sub dx, ax ; BX = timer ticks
111 mov eax, [td_tick_count]
112 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
120 _timer_get_fixed_seconds:
125 call timer_get_stamp64
128 ; Timing in fixed point (16.16) seconds.
129 ; Can be used for up to 1000 hours
130 shld edx, eax, 16 ; Keep 32+11 bits
132 ; edx:eax = number of 1.19Mhz pulses elapsed.
135 ; Make sure we won't divide overflow. Make time wrap at about 9 hours
137 sub edx, ebx ; subtract until negative...
138 jns sub_again ; ...to prevent divide overflow...
139 add edx, ebx ; ...then add in to get correct value.
141 ; eax = fixed point seconds elapsed...
149 _timer_get_fixed_secondsX:
153 call timer_get_stamp64
155 ; Timing in fixed point (16.16) seconds.
156 ; Can be used for up to 1000 hours
157 shld edx, eax, 16 ; Keep 32+11 bits
159 ; edx:eax = number of 1.19Mhz pulses elapsed.
163 sub edx, ebx ; subtract until negative...
164 jns xsub_again ; ...to prevent divide overflow...
165 add edx, ebx ; ...then add in to get correct value.
168 ; eax = fixed point seconds elapsed...
175 _timer_get_approx_seconds:
179 mov eax, [td_tick_count]
180 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
181 shld edx, eax, 16 ; Keep 32+16 bits, for conversion to fixed point
183 ; edx:eax = number of 1.19Mhz pulses elapsed.
187 sub edx, ebx ; subtract until negative...
188 jns approx_sub_again ; ...to prevent divide overflow...
189 add edx, ebx ; ...then add in to get correct value.
192 ; eax = fixed point seconds elapsed...
198 ;----------------------------------------------------------------------------
199 ;Prototype: extern void timer_set_rate(int count_val);
200 ;----------------------------------------------------------------------------
206 ; Make sure eax below or equal to 65535 and above 0
207 ; if its not, make it be 65536 which is normal dos
216 @@@: ; Set the timer rate to eax
218 mov dword [td_tick_count], 0
219 mov [td__timer_cnt], eax
220 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
221 out TCOMMAND, al ; Reset PIT channel 0
222 mov eax, [td__timer_cnt]
230 ;----------------------------------------------------------------------------
231 ;Prototype: extern void timer_set_function( void * function );
232 ;----------------------------------------------------------------------------
234 ; arg1 = near pointer to user function
236 mov eax, [esp+8] ; arg 1
238 mov dword [td_user_function+0], eax ; offset
239 mov word [td_user_function+4], cs ; selector
244 _timer_set_joyhandler:
247 mov dword [td_joystick_poller], eax
251 ;************************************************************************
252 ;************************************************************************
254 ;***** T I M E R _ H A N D L E R *****
256 ;************************************************************************
257 ;************************************************************************
264 mov ax, [cs:__my_ds] ; Interrupt, so point to our data segment
268 ; Increment time counter...
269 inc dword [td_tick_count]
271 mov eax, [td__timer_cnt]
272 add dword [td_dos_timer], eax ; Increment DOS timer
273 cmp dword [td_dos_timer], 65536
274 jb NoChainToOld ; See if we need to chain to DOS 18.2
275 and dword [td_dos_timer], 0ffffh
278 ; Call the original DOS handler....
281 call far dword [td_org_interrupt]
283 jmp NoReset ;old handler has reset, so we don't
287 mov al, 20h ; Reset interrupt controller
291 cmp byte [td_in_timer], 0
294 mov byte [td_in_timer], 1 ; Mark that we're in a timer interrupt...
296 ; Reenable interrupts
297 sti ; Reenable interrupts
299 cmp word [td_user_function+4], 0 ; Check the selector...
302 ; Switch stacks while calling the user-definable function...
306 mov dword [td_saved_stack+0], esp
307 mov word [td_saved_stack+4], ss
308 lss esp, [td_new_stack] ; Switch to new stack
309 call far dword [td_user_function] ; Call new function
310 lss esp, [td_saved_stack] ; Switch back to original stack
316 cmp dword [td_joystick_poller], 0
318 mov eax, [td__timer_cnt]
319 mov dword [td_saved_stack+0], esp
320 mov word [td_saved_stack+4], ss
321 lss esp, [td_new_stack] ; Switch to new stack
324 call dword [td_joystick_poller]
327 lss esp, [td_saved_stack] ; Switch back to original stack
331 mov byte [td_in_timer], 0
334 ;;mov al, 20h ; Reset interrupt controller
339 iretd ; Return from timer interrupt
341 TIMER_LOCKED_CODE_STOP:
343 ;************************************************************************
344 ;************************************************************************
346 ;***** T I M E R _ I N I T *****
348 ;************************************************************************
349 ;************************************************************************
356 cmp byte [td_Installed], 1
357 je NEAR AlreadyInstalled
361 mov dword [td__timer_cnt], 65536 ; Set to BIOS's normal 18.2 Hz
362 mov dword [td_dos_timer], 0 ; clear DOS Interrupt counter
363 mov dword [td_user_function+0], 0 ; offset of user function
364 mov word [td_user_function+4], 0 ; selector of user function
366 lea eax, [ds:td_TimerStack] ; Use EAX as temp stack pointer
367 add eax, STACK_SIZE ; Top of stack minus space for saving old ss:esp
368 mov dword [td_new_stack+0], eax
369 mov word [td_new_stack+4], ds
371 ;--------------- lock data used in interrupt
372 mov eax, (td_TimerStack-TimerData)+STACK_SIZE ;sizeof timer_data
376 and edi, 0ffffh ; si:di = length of region to lock in bytes
378 add ebx, [___djgpp_base_address]
381 and ecx, 0ffffh ; bx:cx = start of linear address to lock
382 mov eax, 0600h ; DPMI lock address function
385 int 3 ; LOCK FAILED!!
387 ;--------------- lock code used in interrupt
388 mov eax, TIMER_LOCKED_CODE_STOP
389 sub eax, TIMER_LOCKED_CODE_START
390 inc eax ; EAX = size of timer interrupt handler
394 and edi, 0ffffh ; si:di = length of region to lock in bytes
395 mov ebx, TIMER_LOCKED_CODE_START
396 add ebx, [___djgpp_base_address]
399 and ecx, 0ffffh ; bx:cx = start of linear address to lock
400 mov eax, 0600h ; DPMI lock address function
402 jnc @@@@@ ;This is getting fun
403 int 3 ; LOCK FAILED!!
406 ;**************************************************************
407 ;******************* SAVE OLD INT8 HANDLER ********************
408 ;**************************************************************
412 mov dword [td_org_interrupt+0],edx
413 mov word [td_org_interrupt+4],cx
415 ;**************************************************************
416 ;***************** INSTALL NEW INT8 HANDLER *******************
417 ;**************************************************************
421 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
422 out TCOMMAND, al ; Reset PIT channel 0
423 mov eax, [td__timer_cnt]
428 mov dword [td_tick_count], 0
429 mov byte [td_Installed],1
433 mov edx,timer_handler
439 push dword _timer_close
451 ;************************************************************************
452 ;************************************************************************
454 ;***** T I M E R _ C L O S E _ *****
456 ;************************************************************************
457 ;************************************************************************
465 cmp byte [td_Installed], 0
467 mov byte [td_Installed], 0
469 ;**************************************************************
470 ;***************** RESTORE OLD INT8 HANDLER *******************
471 ;**************************************************************
474 mov al, 36h ; count in binary, mode 3, load low byte then hi byte, counter 0: 00 11 011 0
475 out TCOMMAND, al ; Reser PIT channel 0
483 mov edx,dword [td_org_interrupt+0]
484 mov cx,word [td_org_interrupt+4]
489 cmp dword [td_nested_counter], 0
490 je NoNestedInterrupts
491 mov eax, [td_nested_counter]