1 ; THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
2 ; SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
3 ; END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
4 ; ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
5 ; IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
6 ; SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
7 ; FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
8 ; CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
9 ; AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
10 ; COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
11 ;***************************************************************************
12 ;***************************************************************************
14 ;***** T I M E R . A S M *****
17 ;***** PROCEDURES *****
21 ;***** VARIABLES *****
24 ;***** CONSTANTS *****
27 ;***************************************************************************
28 ;***************************************************************************
32 ;************************************************************************
33 ;**************** FLAT MODEL DATA SEGMENT STUFF *************************
34 ;************************************************************************
36 _DATA SEGMENT BYTE PUBLIC USE32 'DATA'
41 STACK_SIZE EQU 4096 ; A 4K stack
65 TimerStack db STACK_SIZE dup (?)
68 TimerData TIMER_DATA <>
75 ;************************************************************************
76 ;**************** FLAT MODEL CODE SEGMENT STUFF *************************
77 ;************************************************************************
79 _TEXT SEGMENT BYTE PUBLIC USE32 'CODE'
87 TIMER_LOCKED_CODE_START:
91 PUBLIC timer_get_stamp64
94 ; Return a 64-bit stamp that is the number of 1.19Mhz pulses
95 ; since the time was initialized. Returns in EDX:EAX.
96 ; Also, interrupts must be disabled.
98 xor eax, eax ; Clear all of EAX
99 out TCOMMAND, al ; Tell timer to latch
101 mov al, 0ah ; Find if interrupt pending
108 in al, TDATA ; Read in lo byte
110 in al, TDATA ; Read in hi byte
113 mov eax, TimerData._timer_cnt
119 mov eax, TimerData.tick_count
120 imul TimerData._timer_cnt ; edx:eax = Number of 1.19 MHz ticks elapsed...
128 in al, TDATA ; Read in lo byte
130 in al, TDATA ; Read in hi byte
131 xchg ah, al ; arrange em correctly
132 mov edx, TimerData._timer_cnt
133 sub dx, ax ; BX = timer ticks
138 mov eax, TimerData.tick_count
139 imul TimerData._timer_cnt ; edx:eax = Number of 1.19 MHz ticks elapsed...
147 PUBLIC timer_get_fixed_seconds_
149 timer_get_fixed_seconds_:
154 call timer_get_stamp64
157 ; Timing in fixed point (16.16) seconds.
158 ; Can be used for up to 1000 hours
159 shld edx, eax, 16 ; Keep 32+11 bits
161 ; edx:eax = number of 1.19Mhz pulses elapsed.
164 ; Make sure we won't divide overflow. Make time wrap at about 9 hours
165 sub_again: sub edx, ebx ; subtract until negative...
166 jns sub_again ; ...to prevent divide overflow...
167 add edx, ebx ; ...then add in to get correct value.
169 ; eax = fixed point seconds elapsed...
176 PUBLIC timer_get_fixed_secondsX_
178 timer_get_fixed_secondsX_:
182 call timer_get_stamp64
184 ; Timing in fixed point (16.16) seconds.
185 ; Can be used for up to 1000 hours
186 shld edx, eax, 16 ; Keep 32+11 bits
188 ; edx:eax = number of 1.19Mhz pulses elapsed.
191 xsub_again: sub edx, ebx ; subtract until negative...
192 jns xsub_again ; ...to prevent divide overflow...
193 add edx, ebx ; ...then add in to get correct value.
196 ; eax = fixed point seconds elapsed...
203 PUBLIC timer_get_approx_seconds_
204 timer_get_approx_seconds_:
208 mov eax, TimerData.tick_count
209 imul TimerData._timer_cnt ; edx:eax = Number of 1.19 MHz ticks elapsed...
210 shld edx, eax, 16 ; Keep 32+16 bits, for conversion to fixed point
212 ; edx:eax = number of 1.19Mhz pulses elapsed.
215 approx_sub_again: sub edx, ebx ; subtract until negative...
216 jns approx_sub_again ; ...to prevent divide overflow...
217 add edx, ebx ; ...then add in to get correct value.
220 ; eax = fixed point seconds elapsed...
228 ;extern void timer_set_rate(int count_val);
229 ;extern void timer_set_function( void _far * function );
231 PUBLIC timer_set_rate_
236 ; Make sure eax below or equal to 65535 and above 0
237 ; if its not, make it be 65536 which is normal dos
245 @@: ; Set the timer rate to eax
247 mov TimerData.tick_count, 0
248 mov TimerData._timer_cnt, eax
249 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
250 out TCOMMAND, al ; Reset PIT channel 0
251 mov eax, TimerData._timer_cnt
259 PUBLIC timer_set_function_
261 ; dx:eax = far pointer to user function
264 mov dword ptr TimerData.user_function[0], eax ; offset
265 mov word ptr TimerData.user_function[4], dx ; selector
270 PUBLIC timer_set_joyhandler_
271 timer_set_joyhandler_:
273 mov TimerData.joystick_poller, eax
281 mov ecx, [ds:046Ch] ; Get Current DOS Ticks
292 ;************************************************************************
293 ;************************************************************************
295 ;***** T I M E R _ H A N D L E R *****
297 ;************************************************************************
298 ;************************************************************************
305 mov ax, DGROUP ; Interrupt, so point to our data segment
309 ; Increment time counter...
310 inc TimerData.tick_count
312 mov eax, TimerData._timer_cnt
313 add TimerData.dos_timer, eax ; Increment DOS timer
314 cmp TimerData.dos_timer, 65536
315 jb NoChainToOld ; See if we need to chain to DOS 18.2
316 and TimerData.dos_timer, 0ffffh
319 ; Call the original DOS handler....
322 call fword ptr [TimerData.org_interrupt]
324 jmp NoReset ;old handler has reset, so we don't
328 mov al, 20h ; Reset interrupt controller
332 cmp TimerData.in_timer, 0
335 mov TimerData.in_timer, 1 ; Mark that we're in a timer interrupt...
337 ; Reenable interrupts
338 sti ; Reenable interrupts
340 cmp word ptr TimerData.user_function[4], 0 ; Check the selector...
343 ; Switch stacks while calling the user-definable function...
347 mov dword ptr TimerData.saved_stack[0], esp
348 mov word ptr TimerData.saved_stack[4], ss
349 lss esp, TimerData.new_stack ; Switch to new stack
350 call fword ptr [TimerData.user_function] ; Call new function
351 lss esp, TimerData.saved_stack ; Switch back to original stack
357 cmp dword ptr TimerData.joystick_poller, 0
359 mov eax, TimerData._timer_cnt
360 mov dword ptr TimerData.saved_stack[0], esp
361 mov word ptr TimerData.saved_stack[4], ss
362 lss esp, TimerData.new_stack ; Switch to new stack
363 call dword ptr TimerData.joystick_poller
364 lss esp, TimerData.saved_stack ; Switch back to original stack
368 mov TimerData.in_timer, 0
371 ;;mov al, 20h ; Reset interrupt controller
376 iretd ; Return from timer interrupt
379 TIMER_LOCKED_CODE_STOP:
381 ;************************************************************************
382 ;************************************************************************
384 ;***** T I M E R _ I N I T *****
386 ;************************************************************************
387 ;************************************************************************
397 cmp TimerData.Installed, 1
400 mov TimerData._timer_cnt, 65536 ; Set to BIOS's normal 18.2 Hz
401 mov TimerData.dos_timer, 0 ; clear DOS Interrupt counter
402 mov dword ptr TimerData.user_function[0], 0 ; offset of user function
403 mov word ptr TimerData.user_function[4], 0 ; selector of user function
405 lea eax, ds:[TimerData.TimerStack] ; Use EAX as temp stack pointer
406 add eax, STACK_SIZE ; Top of stack minus space for saving old ss:esp
407 mov dword ptr TimerData.new_stack[0], eax
408 mov word ptr TimerData.new_stack[4], ds
410 ;--------------- lock data used in interrupt
411 mov eax, SIZEOF TIMER_DATA
415 and edi, 0ffffh ; si:di = length of region to lock in bytes
416 lea ebx, ds:TimerData
417 lea ecx, ds:TimerData
419 and ecx, 0ffffh ; bx:cx = start of linear address to lock
420 mov eax, 0600h ; DPMI lock address function
423 int 3 ; LOCK FAILED!!
425 ;--------------- lock code used in interrupt
426 lea eax, cs:TIMER_LOCKED_CODE_STOP
427 lea ecx, cs:TIMER_LOCKED_CODE_START
429 inc eax ; EAX = size of timer interrupt handler
433 and edi, 0ffffh ; si:di = length of region to lock in bytes
434 lea ebx, cs:TIMER_LOCKED_CODE_START
435 lea ecx, cs:TIMER_LOCKED_CODE_START
437 and ecx, 0ffffh ; bx:cx = start of linear address to lock
438 mov eax, 0600h ; DPMI lock address function
441 int 3 ; LOCK FAILED!!
444 ;**************************************************************
445 ;******************* SAVE OLD INT8 HANDLER ********************
446 ;**************************************************************
447 mov eax, 03508h ; DOS Get Vector 08h
450 mov dword ptr TimerData.org_interrupt[0], ebx ; offset of user function
451 mov word ptr TimerData.org_interrupt[4], es ; selector of user function
453 ;**************************************************************
454 ;***************** INSTALL NEW INT8 HANDLER *******************
455 ;**************************************************************
459 mov al, 34h ; count in binary, mode 2, load low byte then hi byte, counter 0: 00 11 010 0
460 out TCOMMAND, al ; Reset PIT channel 0
461 mov eax, TimerData._timer_cnt
466 mov TimerData.tick_count, 0
467 mov TimerData.Installed,1
469 mov eax, 02508h ; DOS Set Vector 08h
470 mov edx, offset timer_handler ; Point DS:EDX to new handler
477 lea eax, cs:timer_close_
489 ;************************************************************************
490 ;************************************************************************
492 ;***** T I M E R _ C L O S E _ *****
494 ;************************************************************************
495 ;************************************************************************
505 cmp TimerData.Installed, 0
507 mov TimerData.Installed, 0
509 ;**************************************************************
510 ;***************** RESTORE OLD INT9 HANDLER *******************
511 ;**************************************************************
514 mov al, 36h ; count in binary, mode 3, load low byte then hi byte, counter 0: 00 11 011 0
515 out TCOMMAND, al ; Reser PIT channel 0
522 mov eax, 02508h ; DOS Set Vector 08h
523 mov edx, dword ptr TimerData.org_interrupt[0]
524 mov ds, word ptr TimerData.org_interrupt[4]
530 cmp TimerData.nested_counter, 0
531 je NoNestedInterrupts
532 mov eax, TimerData.nested_counter