2 ; $Source: /cvs/cvsroot/d2x/arch/dos/timer.asm,v $
5 ; $Date: 2001-10-19 09:01:56 $
9 ; $Log: not supported by cvs2svn $
10 ; Revision 1.2 2001/01/29 13:35:08 bradleyb
11 ; Fixed build system, minor fixes
19 [EXTERN ___djgpp_base_address]
21 [GLOBAL _timer_get_fixed_seconds]
22 [GLOBAL _timer_get_fixed_secondsX]
23 [GLOBAL _timer_get_approx_seconds]
24 [GLOBAL _timer_set_rate]
25 [GLOBAL _timer_set_function]
26 [GLOBAL _timer_set_joyhandler]
52 td_in_timer equ TimerData
53 td_nested_counter equ td_in_timer+1
54 td__timer_cnt equ td_nested_counter+4
55 td_dos_timer equ td__timer_cnt+4
56 td_joystick_poller equ td_dos_timer+4
57 td_user_function equ td_joystick_poller+4
58 td_org_interrupt equ td_user_function+6
59 td_saved_stack equ td_org_interrupt+6
60 td_new_stack equ td_saved_stack+6
61 td_tick_count equ td_new_stack+6
62 td_Installed equ td_tick_count+4
63 td_TimerStack equ td_Installed+1
68 TIMER_LOCKED_CODE_START:
73 ; Return a 64-bit stamp that is the number of 1.19Mhz pulses
74 ; since the time was initialized. Returns in EDX:EAX.
75 ; Also, interrupts must be disabled.
77 xor eax, eax ; Clear all of EAX
78 out TCOMMAND, al ; Tell timer to latch
80 mov al, 0ah ; Find if interrupt pending
88 in al, TDATA ; Read in lo byte
90 in al, TDATA ; Read in hi byte
93 mov eax, [td__timer_cnt]
99 mov eax, [td_tick_count]
100 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
108 in al, TDATA ; Read in lo byte
110 in al, TDATA ; Read in hi byte
111 xchg ah, al ; arrange em correctly
112 mov edx, [td__timer_cnt]
113 sub dx, ax ; BX = timer ticks
118 mov eax, [td_tick_count]
119 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
127 _timer_get_fixed_seconds:
132 call timer_get_stamp64
135 ; Timing in fixed point (16.16) seconds.
136 ; Can be used for up to 1000 hours
137 shld edx, eax, 16 ; Keep 32+11 bits
139 ; edx:eax = number of 1.19Mhz pulses elapsed.
142 ; Make sure we won't divide overflow. Make time wrap at about 9 hours
144 sub edx, ebx ; subtract until negative...
145 jns sub_again ; ...to prevent divide overflow...
146 add edx, ebx ; ...then add in to get correct value.
148 ; eax = fixed point seconds elapsed...
156 _timer_get_fixed_secondsX:
160 call timer_get_stamp64
162 ; Timing in fixed point (16.16) seconds.
163 ; Can be used for up to 1000 hours
164 shld edx, eax, 16 ; Keep 32+11 bits
166 ; edx:eax = number of 1.19Mhz pulses elapsed.
170 sub edx, ebx ; subtract until negative...
171 jns xsub_again ; ...to prevent divide overflow...
172 add edx, ebx ; ...then add in to get correct value.
175 ; eax = fixed point seconds elapsed...
182 _timer_get_approx_seconds:
186 mov eax, [td_tick_count]
187 imul dword [td__timer_cnt] ; edx:eax = Number of 1.19 MHz ticks elapsed...
188 shld edx, eax, 16 ; Keep 32+16 bits, for conversion to fixed point
190 ; edx:eax = number of 1.19Mhz pulses elapsed.
194 sub edx, ebx ; subtract until negative...
195 jns approx_sub_again ; ...to prevent divide overflow...
196 add edx, ebx ; ...then add in to get correct value.
199 ; eax = fixed point seconds elapsed...
205 ;----------------------------------------------------------------------------
206 ;Prototype: extern void timer_set_rate(int count_val);
207 ;----------------------------------------------------------------------------
213 ; Make sure eax below or equal to 65535 and above 0
214 ; if its not, make it be 65536 which is normal dos
223 @@@: ; Set the timer rate to eax
225 mov dword [td_tick_count], 0
226 mov [td__timer_cnt], eax
227 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
228 out TCOMMAND, al ; Reset PIT channel 0
229 mov eax, [td__timer_cnt]
237 ;----------------------------------------------------------------------------
238 ;Prototype: extern void timer_set_function( void * function );
239 ;----------------------------------------------------------------------------
241 ; arg1 = near pointer to user function
243 mov eax, [esp+8] ; arg 1
245 mov dword [td_user_function+0], eax ; offset
246 mov word [td_user_function+4], cs ; selector
251 _timer_set_joyhandler:
254 mov dword [td_joystick_poller], eax
258 ;************************************************************************
259 ;************************************************************************
261 ;***** T I M E R _ H A N D L E R *****
263 ;************************************************************************
264 ;************************************************************************
271 mov ax, [cs:__my_ds] ; Interrupt, so point to our data segment
275 ; Increment time counter...
276 inc dword [td_tick_count]
278 mov eax, [td__timer_cnt]
279 add dword [td_dos_timer], eax ; Increment DOS timer
280 cmp dword [td_dos_timer], 65536
281 jb NoChainToOld ; See if we need to chain to DOS 18.2
282 and dword [td_dos_timer], 0ffffh
285 ; Call the original DOS handler....
288 call far dword [td_org_interrupt]
290 jmp NoReset ;old handler has reset, so we don't
294 mov al, 20h ; Reset interrupt controller
298 cmp byte [td_in_timer], 0
301 mov byte [td_in_timer], 1 ; Mark that we're in a timer interrupt...
303 ; Reenable interrupts
304 sti ; Reenable interrupts
306 cmp word [td_user_function+4], 0 ; Check the selector...
309 ; Switch stacks while calling the user-definable function...
313 mov dword [td_saved_stack+0], esp
314 mov word [td_saved_stack+4], ss
315 lss esp, [td_new_stack] ; Switch to new stack
316 call far dword [td_user_function] ; Call new function
317 lss esp, [td_saved_stack] ; Switch back to original stack
323 cmp dword [td_joystick_poller], 0
325 mov eax, [td__timer_cnt]
326 mov dword [td_saved_stack+0], esp
327 mov word [td_saved_stack+4], ss
328 lss esp, [td_new_stack] ; Switch to new stack
331 call dword [td_joystick_poller]
334 lss esp, [td_saved_stack] ; Switch back to original stack
338 mov byte [td_in_timer], 0
341 ;;mov al, 20h ; Reset interrupt controller
346 iretd ; Return from timer interrupt
348 TIMER_LOCKED_CODE_STOP:
350 ;************************************************************************
351 ;************************************************************************
353 ;***** T I M E R _ I N I T *****
355 ;************************************************************************
356 ;************************************************************************
363 cmp byte [td_Installed], 1
364 je NEAR AlreadyInstalled
368 mov dword [td__timer_cnt], 65536 ; Set to BIOS's normal 18.2 Hz
369 mov dword [td_dos_timer], 0 ; clear DOS Interrupt counter
370 mov dword [td_user_function+0], 0 ; offset of user function
371 mov word [td_user_function+4], 0 ; selector of user function
373 lea eax, [ds:td_TimerStack] ; Use EAX as temp stack pointer
374 add eax, STACK_SIZE ; Top of stack minus space for saving old ss:esp
375 mov dword [td_new_stack+0], eax
376 mov word [td_new_stack+4], ds
378 ;--------------- lock data used in interrupt
379 mov eax, (td_TimerStack-TimerData)+STACK_SIZE ;sizeof timer_data
383 and edi, 0ffffh ; si:di = length of region to lock in bytes
385 add ebx, [___djgpp_base_address]
388 and ecx, 0ffffh ; bx:cx = start of linear address to lock
389 mov eax, 0600h ; DPMI lock address function
392 int 3 ; LOCK FAILED!!
394 ;--------------- lock code used in interrupt
395 mov eax, TIMER_LOCKED_CODE_STOP
396 sub eax, TIMER_LOCKED_CODE_START
397 inc eax ; EAX = size of timer interrupt handler
401 and edi, 0ffffh ; si:di = length of region to lock in bytes
402 mov ebx, TIMER_LOCKED_CODE_START
403 add ebx, [___djgpp_base_address]
406 and ecx, 0ffffh ; bx:cx = start of linear address to lock
407 mov eax, 0600h ; DPMI lock address function
409 jnc @@@@@ ;This is getting fun
410 int 3 ; LOCK FAILED!!
413 ;**************************************************************
414 ;******************* SAVE OLD INT8 HANDLER ********************
415 ;**************************************************************
419 mov dword [td_org_interrupt+0],edx
420 mov word [td_org_interrupt+4],cx
422 ;**************************************************************
423 ;***************** INSTALL NEW INT8 HANDLER *******************
424 ;**************************************************************
428 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
429 out TCOMMAND, al ; Reset PIT channel 0
430 mov eax, [td__timer_cnt]
435 mov dword [td_tick_count], 0
436 mov byte [td_Installed],1
440 mov edx,timer_handler
446 push dword _timer_close
458 ;************************************************************************
459 ;************************************************************************
461 ;***** T I M E R _ C L O S E _ *****
463 ;************************************************************************
464 ;************************************************************************
472 cmp byte [td_Installed], 0
474 mov byte [td_Installed], 0
476 ;**************************************************************
477 ;***************** RESTORE OLD INT8 HANDLER *******************
478 ;**************************************************************
481 mov al, 36h ; count in binary, mode 3, load low byte then hi byte, counter 0: 00 11 011 0
482 out TCOMMAND, al ; Reser PIT channel 0
490 mov edx,dword [td_org_interrupt+0]
491 mov cx,word [td_org_interrupt+4]
496 cmp dword [td_nested_counter], 0
497 je NoNestedInterrupts
498 mov eax, [td_nested_counter]