]> icculus.org git repositories - btb/d2x.git/blob - unused/bios/timer.asm
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / unused / bios / timer.asm
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 ;***************************************************************************
13 ;*****                                                                 *****
14 ;*****                     T I M E R . A S M                           *****
15 ;*****                                                                 *****
16 ;*****                                                                 *****
17 ;***** PROCEDURES                                                      *****
18 ;*****                                                                 *****
19 ;*****                                                                 *****
20 ;*****                                                                 *****
21 ;***** VARIABLES                                                       *****
22 ;*****                                                                 *****
23 ;*****                                                                 *****
24 ;***** CONSTANTS                                                       *****
25 ;*****                                                                 *****
26 ;*****                                                                 *****
27 ;***************************************************************************
28 ;***************************************************************************
29
30 .386
31
32 ;************************************************************************
33 ;**************** FLAT MODEL DATA SEGMENT STUFF *************************
34 ;************************************************************************
35
36 _DATA   SEGMENT BYTE PUBLIC USE32 'DATA'
37
38 TDATA           EQU     40h
39 TCOMMAND        EQU     43h
40 PIC             EQU     020h
41 STACK_SIZE      EQU     4096    ; A 4K stack
42
43 TIMER_DATA STRUCT   
44         in_timer        db  0
45
46         nested_counter  dd      0
47
48         _timer_cnt      dd  65536
49         dos_timer       dd  ?
50
51         joystick_poller dd  0
52
53         user_function   df  0
54         
55         org_interrupt   df  0   
56
57         saved_stack     df  0
58
59         new_stack       df  0
60
61         tick_count      dd  0
62
63         Installed db    0
64
65         TimerStack      db  STACK_SIZE dup (?)          
66 TIMER_DATA ENDS
67
68         TimerData       TIMER_DATA <>   
69
70 _DATA   ENDS
71
72 DGROUP  GROUP _DATA
73
74
75 ;************************************************************************
76 ;**************** FLAT MODEL CODE SEGMENT STUFF *************************
77 ;************************************************************************
78
79 _TEXT   SEGMENT BYTE PUBLIC USE32 'CODE'
80
81                 ASSUME  ds:_DATA
82                 ASSUME  cs:_TEXT
83
84 INCLUDE PSMACROS.INC
85 INCLUDE FIX.INC
86
87 TIMER_LOCKED_CODE_START:
88
89                 extn atexit_
90
91 PUBLIC timer_get_stamp64
92
93 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.
97
98                 xor     eax, eax            ; Clear all of EAX
99                 out     TCOMMAND, al        ; Tell timer to latch
100
101                 mov     al, 0ah             ; Find if interrupt pending
102                 out     PIC, al
103                 jmp     @f
104 @@:             in      al, PIC
105                 and     eax, 01b
106                 jz      NoInterrupt
107
108                 in      al, TDATA           ; Read in lo byte
109                 mov     dl, al
110                 in      al, TDATA           ; Read in hi byte
111                 mov     dh, al
112                 and     edx, 0ffffh
113                 mov     eax, TimerData._timer_cnt
114                 shl     eax, 1          
115                 sub     eax, edx
116                         
117                 push    ebx
118                 mov     ebx, eax
119                 mov     eax, TimerData.tick_count
120                 imul    TimerData._timer_cnt    ; edx:eax = Number of 1.19 MHz ticks elapsed...
121                 add     eax, ebx
122                 adc     edx, 0                          
123                 pop     ebx
124
125                 ret
126
127 NoInterrupt:
128                 in      al, TDATA           ; Read in lo byte
129                 mov     ah, al
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
134                 mov     ax, dx
135
136                 push    ebx
137                 mov     ebx, eax
138                 mov     eax, TimerData.tick_count
139                 imul    TimerData._timer_cnt    ; edx:eax = Number of 1.19 MHz ticks elapsed...
140                 add     eax, ebx
141                 adc     edx, 0                          
142                 pop     ebx
143
144                 ret
145
146
147 PUBLIC  timer_get_fixed_seconds_
148
149 timer_get_fixed_seconds_:
150                 push    ebx
151                 push    edx
152
153                 cli
154                 call    timer_get_stamp64
155                 sti
156
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
160                 shl     eax, 16                 
161                 ; edx:eax = number of 1.19Mhz pulses elapsed.
162                 mov     ebx, 1193180
163
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.
168                 div     ebx
169                 ; eax = fixed point seconds elapsed...
170
171                 pop     edx
172                 pop     ebx
173
174                 ret
175
176 PUBLIC  timer_get_fixed_secondsX_
177
178 timer_get_fixed_secondsX_:
179                 push    ebx
180                 push    edx
181
182                 call    timer_get_stamp64
183
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
187                 shl     eax, 16                 
188                 ; edx:eax = number of 1.19Mhz pulses elapsed.
189                 mov     ebx, 1193180
190
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.
194
195                 div     ebx
196                 ; eax = fixed point seconds elapsed...
197
198                 pop     edx
199                 pop     ebx
200
201                 ret
202
203 PUBLIC timer_get_approx_seconds_
204 timer_get_approx_seconds_:
205         push    ebx
206         push    edx
207
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
211         shl     eax, 16                 
212         ; edx:eax = number of 1.19Mhz pulses elapsed.
213         mov     ebx, 1193180
214
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.
218
219         div     ebx
220         ; eax = fixed point seconds elapsed...
221
222         pop     edx
223         pop     ebx
224         ret
225
226
227
228 ;extern void timer_set_rate(int count_val);
229 ;extern void timer_set_function( void _far * function );
230
231 PUBLIC  timer_set_rate_
232 timer_set_rate_:
233         ; eax = rate
234         pushad
235
236         ; Make sure eax below or equal to 65535 and above 0
237         ; if its not, make it be 65536 which is normal dos
238         ; timing.
239         cmp     eax, 65535
240         jbe     @f
241         mov     eax, 65536
242 @@:     cmp     eax, 0
243         jne     @f
244         mov     eax, 65536
245 @@:     ; Set the timer rate to eax
246         cli
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
252         out     TDATA, al
253         mov     al, ah
254         out     TDATA, al
255         sti
256         popad
257         ret
258
259 PUBLIC  timer_set_function_
260 timer_set_function_:
261         ; dx:eax = far pointer to user function
262         pushad
263         cli
264         mov     dword ptr TimerData.user_function[0], eax       ; offset
265         mov     word ptr TimerData.user_function[4], dx         ; selector
266         sti
267         popad
268         ret
269
270 PUBLIC timer_set_joyhandler_
271 timer_set_joyhandler_:
272         cli
273         mov     TimerData.joystick_poller, eax
274         sti
275         ret
276
277 PUBLIC timer_delay_
278 timer_delay_:
279         pushad
280         mov     edx, 18
281         mov     ecx, [ds:046Ch]         ; Get Current DOS Ticks
282         fixmul  edx     
283         add     ecx, eax
284 timeloop:
285         cmp     ecx, [ds:046ch]
286         jg      timeloop
287         popad
288         ret
289
290
291
292 ;************************************************************************
293 ;************************************************************************
294 ;*****                                                              *****
295 ;*****                T I M E R _ H A N D L E R                     *****
296 ;*****                                                              *****
297 ;************************************************************************
298 ;************************************************************************
299
300 timer_handler:
301                 push    ds
302                 push    es
303                 push    eax
304
305                 mov     ax, DGROUP       ; Interrupt, so point to our data segment
306                 mov     ds, ax
307                 mov     es, ax
308
309                 ; Increment time counter...
310                 inc     TimerData.tick_count
311
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
317
318                 ;
319                 ; Call the original DOS handler....
320                 ;
321                 pushfd
322                 call    fword ptr [TimerData.org_interrupt]
323
324                 jmp     NoReset         ;old handler has reset, so we don't
325
326 NoChainToOld:
327                 ; Reset controller
328                 mov     al, 20h         ; Reset interrupt controller
329                 out     20h, al
330
331 NoReset:
332                 cmp     TimerData.in_timer, 0
333                 jne     ExitInterrupt
334
335                 mov     TimerData.in_timer, 1           ; Mark that we're in a timer interrupt...
336
337                 ; Reenable interrupts
338                 sti                     ; Reenable interrupts
339
340                 cmp     word ptr TimerData.user_function[4], 0          ; Check the selector...
341                 je      NoUserFunction
342
343                 ; Switch stacks while calling the user-definable function...
344                 pushad
345                 push    fs
346                 push    gs
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
352                 pop     gs
353                 pop     fs
354                 popad
355
356 NoUserFunction: 
357                 cmp     dword ptr TimerData.joystick_poller, 0
358                 je      NoJoyPolling
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
365
366 NoJoyPolling:
367                 cli
368                 mov     TimerData.in_timer, 0
369
370 ExitInterrupt:
371                 ;;mov     al, 20h         ; Reset interrupt controller
372                 ;;out     20h, al
373                 pop     eax
374                 pop     es
375                 pop     ds
376                 iretd                           ; Return from timer interrupt
377
378
379 TIMER_LOCKED_CODE_STOP:
380
381 ;************************************************************************
382 ;************************************************************************
383 ;*****                                                              *****
384 ;*****                   T I M E R _ I N I T                        *****
385 ;*****                                                              *****
386 ;************************************************************************
387 ;************************************************************************
388
389
390 PUBLIC  timer_init_
391
392 timer_init_:
393                 pushad
394                 push    ds
395                 push    es
396
397                 cmp     TimerData.Installed, 1
398                 je      AlreadyInstalled
399
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
404
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
409
410                 ;--------------- lock data used in interrupt
411                 mov     eax, SIZEOF TIMER_DATA
412                 mov     esi, eax
413                 shr     esi, 16                 
414                 mov     edi, eax
415                 and     edi, 0ffffh     ; si:di = length of region to lock in bytes
416                 lea     ebx, ds:TimerData
417                 lea     ecx, ds:TimerData
418                 shr     ebx, 16
419                 and     ecx, 0ffffh     ; bx:cx = start of linear address to lock
420                 mov     eax, 0600h      ; DPMI lock address function
421                 int     31h             ; call dpmi
422                 jnc     @f
423                 int     3               ; LOCK FAILED!!
424 @@:
425                 ;--------------- lock code used in interrupt
426                 lea     eax, cs:TIMER_LOCKED_CODE_STOP
427                 lea     ecx, cs:TIMER_LOCKED_CODE_START
428                 sub     eax, ecx
429                 inc     eax             ; EAX = size of timer interrupt handler
430                 mov     esi, eax
431                 shr     esi, 16                 
432                 mov     edi, eax
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
436                 shr     ebx, 16
437                 and     ecx, 0ffffh     ; bx:cx = start of linear address to lock
438                 mov     eax, 0600h      ; DPMI lock address function
439                 int     31h             ; call dpmi
440                 jnc     @f
441                 int     3               ; LOCK FAILED!!
442 @@:
443
444                 ;**************************************************************
445                 ;******************* SAVE OLD INT8 HANDLER ********************
446                 ;**************************************************************
447                 mov     eax, 03508h             ; DOS Get Vector 08h
448                 int     21h                     ; Call DOS
449
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
452
453                 ;**************************************************************
454                 ;***************** INSTALL NEW INT8 HANDLER *******************
455                 ;**************************************************************
456
457                 cli
458
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
462                 out     TDATA, al
463                 mov     al, ah
464                 out     TDATA, al
465
466                 mov     TimerData.tick_count, 0
467                 mov     TimerData.Installed,1
468
469                 mov     eax, 02508h             ; DOS Set Vector 08h
470                 mov     edx, offset timer_handler  ; Point DS:EDX to new handler
471                 mov     bx, cs
472                 push    ds
473                 mov     ds, bx
474                 int     21h
475                 pop     ds
476                 sti
477                 lea     eax, cs:timer_close_
478                 call    atexit_
479
480 AlreadyInstalled:
481
482                 pop     es
483                 pop     ds
484                 popad
485
486                 ret
487
488
489 ;************************************************************************
490 ;************************************************************************
491 ;*****                                                              *****
492 ;*****                  T I M E R _ C L O S E _                     *****
493 ;*****                                                              *****
494 ;************************************************************************
495 ;************************************************************************
496
497 PUBLIC  timer_close_
498
499 timer_close_:
500                 push    eax
501                 push    edx
502                 push    ds
503
504
505                 cmp     TimerData.Installed, 0
506                 je      NotInstalled
507                 mov     TimerData.Installed, 0
508
509                 ;**************************************************************
510                 ;***************** RESTORE OLD INT9 HANDLER *******************
511                 ;**************************************************************
512
513                 cli
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
516                 mov     ax, 0h
517                 out     TDATA, al
518                 mov     al, ah
519                 out     TDATA, al
520
521                 push    ds
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]
525                 int     21h
526                 pop     ds
527
528                 sti
529                 
530                 cmp     TimerData.nested_counter, 0
531                 je      NoNestedInterrupts
532                 mov     eax, TimerData.nested_counter
533                 ;int    3               ; Get John!!
534         
535 NoNestedInterrupts:
536                 
537
538 NotInstalled:
539                 pop     ds
540                 pop     edx
541                 pop     eax
542
543                 ret
544
545
546 _TEXT           ENDS
547
548
549                 END