2 ; $Source: /cvs/cvsroot/d2x/arch/dos_timer.asm,v $
5 ; $Date: 2001-01-29 13:35:08 $
9 ; $Log: not supported by cvs2svn $
16 [EXTERN ___djgpp_base_address]
18 [GLOBAL _timer_get_fixed_seconds]
19 [GLOBAL _timer_get_fixed_secondsX]
20 [GLOBAL _timer_get_approx_seconds]
21 [GLOBAL _timer_set_rate]
22 [GLOBAL _timer_set_function]
23 [GLOBAL _timer_set_joyhandler]
49 td_in_timer equ TimerData
50 td_nested_counter equ td_in_timer+1
51 td__timer_cnt equ td_nested_counter+4
52 td_dos_timer equ td__timer_cnt+4
53 td_joystick_poller equ td_dos_timer+4
54 td_user_function equ td_joystick_poller+4
55 td_org_interrupt equ td_user_function+6
56 td_saved_stack equ td_org_interrupt+6
57 td_new_stack equ td_saved_stack+6
58 td_tick_count equ td_new_stack+6
59 td_Installed equ td_tick_count+4
60 td_TimerStack equ td_Installed+1
65 TIMER_LOCKED_CODE_START:
70 ; Return a 64-bit stamp that is the number of 1.19Mhz pulses
71 ; since the time was initialized. Returns in EDX:EAX.
72 ; Also, interrupts must be disabled.
74 xor eax, eax ; Clear all of EAX
75 out TCOMMAND, al ; Tell timer to latch
77 mov al, 0ah ; Find if interrupt pending
85 in al, TDATA ; Read in lo byte
87 in al, TDATA ; Read in hi byte
90 mov eax, [td__timer_cnt]
96 mov eax, [td_tick_count]
97 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
105 in al, TDATA ; Read in lo byte
107 in al, TDATA ; Read in hi byte
108 xchg ah, al ; arrange em correctly
109 mov edx, [td__timer_cnt]
110 sub dx, ax ; BX = timer ticks
115 mov eax, [td_tick_count]
116 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
124 _timer_get_fixed_seconds:
129 call timer_get_stamp64
132 ; Timing in fixed point (16.16) seconds.
133 ; Can be used for up to 1000 hours
134 shld edx, eax, 16 ; Keep 32+11 bits
136 ; edx:eax = number of 1.19Mhz pulses elapsed.
139 ; Make sure we won't divide overflow. Make time wrap at about 9 hours
141 sub edx, ebx ; subtract until negative...
142 jns sub_again ; ...to prevent divide overflow...
143 add edx, ebx ; ...then add in to get correct value.
145 ; eax = fixed point seconds elapsed...
153 _timer_get_fixed_secondsX:
157 call timer_get_stamp64
159 ; Timing in fixed point (16.16) seconds.
160 ; Can be used for up to 1000 hours
161 shld edx, eax, 16 ; Keep 32+11 bits
163 ; edx:eax = number of 1.19Mhz pulses elapsed.
167 sub edx, ebx ; subtract until negative...
168 jns xsub_again ; ...to prevent divide overflow...
169 add edx, ebx ; ...then add in to get correct value.
172 ; eax = fixed point seconds elapsed...
179 _timer_get_approx_seconds:
183 mov eax, [td_tick_count]
184 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
185 shld edx, eax, 16 ; Keep 32+16 bits, for conversion to fixed point
187 ; edx:eax = number of 1.19Mhz pulses elapsed.
191 sub edx, ebx ; subtract until negative...
192 jns approx_sub_again ; ...to prevent divide overflow...
193 add edx, ebx ; ...then add in to get correct value.
196 ; eax = fixed point seconds elapsed...
202 ;----------------------------------------------------------------------------
203 ;Prototype: extern void timer_set_rate(int count_val);
204 ;----------------------------------------------------------------------------
210 ; Make sure eax below or equal to 65535 and above 0
211 ; if its not, make it be 65536 which is normal dos
220 @@@: ; Set the timer rate to eax
222 mov dword [td_tick_count], 0
223 mov [td__timer_cnt], eax
224 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
225 out TCOMMAND, al ; Reset PIT channel 0
226 mov eax, [td__timer_cnt]
234 ;----------------------------------------------------------------------------
235 ;Prototype: extern void timer_set_function( void * function );
236 ;----------------------------------------------------------------------------
238 ; arg1 = near pointer to user function
240 mov eax, [esp+8] ; arg 1
242 mov dword [td_user_function+0], eax ; offset
243 mov word [td_user_function+4], cs ; selector
248 _timer_set_joyhandler:
251 mov dword [td_joystick_poller], eax
255 ;************************************************************************
256 ;************************************************************************
258 ;***** T I M E R _ H A N D L E R *****
260 ;************************************************************************
261 ;************************************************************************
268 mov ax, [cs:__my_ds] ; Interrupt, so point to our data segment
272 ; Increment time counter...
273 inc dword [td_tick_count]
275 mov eax, [td__timer_cnt]
276 add dword [td_dos_timer], eax ; Increment DOS timer
277 cmp dword [td_dos_timer], 65536
278 jb NoChainToOld ; See if we need to chain to DOS 18.2
279 and dword [td_dos_timer], 0ffffh
282 ; Call the original DOS handler....
285 call far dword [td_org_interrupt]
287 jmp NoReset ;old handler has reset, so we don't
291 mov al, 20h ; Reset interrupt controller
295 cmp byte [td_in_timer], 0
298 mov byte [td_in_timer], 1 ; Mark that we're in a timer interrupt...
300 ; Reenable interrupts
301 sti ; Reenable interrupts
303 cmp word [td_user_function+4], 0 ; Check the selector...
306 ; Switch stacks while calling the user-definable function...
310 mov dword [td_saved_stack+0], esp
311 mov word [td_saved_stack+4], ss
312 lss esp, [td_new_stack] ; Switch to new stack
313 call far dword [td_user_function] ; Call new function
314 lss esp, [td_saved_stack] ; Switch back to original stack
320 cmp dword [td_joystick_poller], 0
322 mov eax, [td__timer_cnt]
323 mov dword [td_saved_stack+0], esp
324 mov word [td_saved_stack+4], ss
325 lss esp, [td_new_stack] ; Switch to new stack
328 call dword [td_joystick_poller]
331 lss esp, [td_saved_stack] ; Switch back to original stack
335 mov byte [td_in_timer], 0
338 ;;mov al, 20h ; Reset interrupt controller
343 iretd ; Return from timer interrupt
345 TIMER_LOCKED_CODE_STOP:
347 ;************************************************************************
348 ;************************************************************************
350 ;***** T I M E R _ I N I T *****
352 ;************************************************************************
353 ;************************************************************************
360 cmp byte [td_Installed], 1
361 je NEAR AlreadyInstalled
365 mov dword [td__timer_cnt], 65536 ; Set to BIOS's normal 18.2 Hz
366 mov dword [td_dos_timer], 0 ; clear DOS Interrupt counter
367 mov dword [td_user_function+0], 0 ; offset of user function
368 mov word [td_user_function+4], 0 ; selector of user function
370 lea eax, [ds:td_TimerStack] ; Use EAX as temp stack pointer
371 add eax, STACK_SIZE ; Top of stack minus space for saving old ss:esp
372 mov dword [td_new_stack+0], eax
373 mov word [td_new_stack+4], ds
375 ;--------------- lock data used in interrupt
376 mov eax, (td_TimerStack-TimerData)+STACK_SIZE ;sizeof timer_data
380 and edi, 0ffffh ; si:di = length of region to lock in bytes
382 add ebx, [___djgpp_base_address]
385 and ecx, 0ffffh ; bx:cx = start of linear address to lock
386 mov eax, 0600h ; DPMI lock address function
389 int 3 ; LOCK FAILED!!
391 ;--------------- lock code used in interrupt
392 mov eax, TIMER_LOCKED_CODE_STOP
393 sub eax, TIMER_LOCKED_CODE_START
394 inc eax ; EAX = size of timer interrupt handler
398 and edi, 0ffffh ; si:di = length of region to lock in bytes
399 mov ebx, TIMER_LOCKED_CODE_START
400 add ebx, [___djgpp_base_address]
403 and ecx, 0ffffh ; bx:cx = start of linear address to lock
404 mov eax, 0600h ; DPMI lock address function
406 jnc @@@@@ ;This is getting fun
407 int 3 ; LOCK FAILED!!
410 ;**************************************************************
411 ;******************* SAVE OLD INT8 HANDLER ********************
412 ;**************************************************************
416 mov dword [td_org_interrupt+0],edx
417 mov word [td_org_interrupt+4],cx
419 ;**************************************************************
420 ;***************** INSTALL NEW INT8 HANDLER *******************
421 ;**************************************************************
425 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
426 out TCOMMAND, al ; Reset PIT channel 0
427 mov eax, [td__timer_cnt]
432 mov dword [td_tick_count], 0
433 mov byte [td_Installed],1
437 mov edx,timer_handler
443 push dword _timer_close
455 ;************************************************************************
456 ;************************************************************************
458 ;***** T I M E R _ C L O S E _ *****
460 ;************************************************************************
461 ;************************************************************************
469 cmp byte [td_Installed], 0
471 mov byte [td_Installed], 0
473 ;**************************************************************
474 ;***************** RESTORE OLD INT8 HANDLER *******************
475 ;**************************************************************
478 mov al, 36h ; count in binary, mode 3, load low byte then hi byte, counter 0: 00 11 011 0
479 out TCOMMAND, al ; Reser PIT channel 0
487 mov edx,dword [td_org_interrupt+0]
488 mov cx,word [td_org_interrupt+4]
493 cmp dword [td_nested_counter], 0
494 je NoNestedInterrupts
495 mov eax, [td_nested_counter]