home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / bios / timer.asm < prev    next >
Assembly Source File  |  1998-06-08  |  19KB  |  649 lines

  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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  11. ;
  12. ; $Source: f:/miner/source/bios/rcs/timer.asm $
  13. ; $Revision: 1.28 $
  14. ; $Author: matt $
  15. ; $Date: 1995/02/15 01:36:56 $
  16. ;
  17. ; Routines for setting and using system timers
  18. ;
  19. ; $Log: timer.asm $
  20. ; Revision 1.28  1995/02/15  01:36:56  matt
  21. ; Cleaned up code to avoid doing out 20,20 more than once
  22. ; Revision 1.27  1995/02/14  11:39:37  john
  23. ; Fixed bug with joystick handler not having enough
  24. ; stack space under Windows.
  25. ; Revision 1.26  1995/02/09  21:51:39  john
  26. ; Made so that DOS timer interrupt gets called before interrupts are
  27. ; enabled in timer interpt because not doing this cause conflicts with
  28. ; ps2 style mice and smartdrv with write caching enabled that hangs the
  29. ; program and trashes the FAT.
  30. ; Revision 1.25  1995/02/04  15:39:33  john
  31. ; More time interrupt changes.
  32. ; Revision 1.24  1995/02/03  23:25:21  john
  33. ; Made so that when interrupts are nested, the time interrupt still
  34. ; calls the DOS one.
  35. ; Revision 1.23  1995/01/29  19:00:42  john
  36. ; Made latching timer value more readable.
  37. ; Revision 1.22  1995/01/17  10:34:53  mike
  38. ; prevent divide overflows.
  39. ; Revision 1.21  1994/12/15  11:10:54  john
  40. ; Added code that should make DOS 18.2 callbacks 
  41. ; a bit more accurate.
  42. ; Revision 1.20  1994/12/10  12:47:34  john
  43. ; Made so that timer_get_fixed seconds and get_approx seconds are always equal.
  44. ; Revision 1.19  1994/12/10  12:27:34  john
  45. ; Added timer_get_approx_seconds.
  46. ; Revision 1.18  1994/12/10  12:07:14  john
  47. ; Added tick counter variable.
  48. ; Revision 1.17  1994/12/04  11:55:16  john
  49. ; Made stick read at whatever rate the clock is at, not
  50. ; at 18.2 times/second.
  51. ; Revision 1.16  1994/11/28  15:24:10  john
  52. ; Cleaned up timer interrupt a bit.
  53. ; Revision 1.15  1994/11/22  17:00:43  john
  54. ; Made the timer handler fill in ES along with DS.
  55. ; The HMI drivers expect this.
  56. ; Revision 1.14  1994/11/15  12:04:38  john
  57. ; Cleaned up timer code a bit... took out unused functions
  58. ; like timer_get_milliseconds, etc.
  59. ; Revision 1.13  1994/10/05  16:17:40  john
  60. ; Made interrupts more stable.
  61. ; Revision 1.12  1994/09/29  18:29:57  john
  62. ; Enabled interrupts whil calling the user_function.
  63. ; Revision 1.11  1994/09/23  16:00:31  john
  64. ; MAde the timer interrupt switch to a 4K stack
  65. ; before calling the timer_function.
  66. ; Revision 1.10  1994/09/22  16:09:21  john
  67. ; Fixed some virtual memory lockdown problems with timer and
  68. ; joystick.
  69. ; Revision 1.9  1994/04/29  12:13:48  john
  70. ; Locked all memory used during interrupts so that program
  71. ; won't hang when using virtual memory.
  72. ; Revision 1.8  1994/04/28  23:50:49  john
  73. ; Changed calling for init_timer.  Made the function that the
  74. ; timer calls be a far function. All of this was done to make
  75. ; our timer system compatible with the HMI sound stuff.
  76. ; Revision 1.7  1994/02/17  15:57:15  john
  77. ; Changed key libary to C.
  78. ; Revision 1.6  1994/01/18  20:19:17  john
  79. ; Fixed minor flaws with pending interrupts,
  80. ; interfaced with joystick code.
  81. ; Revision 1.5  1994/01/18  13:54:18  john
  82. ; Fixed a few miner flaws.
  83. ; Revision 1.4  1994/01/18  10:58:25  john
  84. ; Added timer_get_fixed_seconds
  85. ; Revision 1.3  1993/12/20  15:40:59  john
  86. ; *** empty log message ***
  87. ; Revision 1.2  1993/09/23  18:08:44  john
  88. ; added code so that timer_init can handle multiple calls.
  89. ; added code so that atexit is called.
  90. ; Revision 1.1  1993/07/10  13:10:43  matt
  91. ; Initial revision
  92. ;
  93. ;
  94.  
  95. ;***************************************************************************
  96. ;***************************************************************************
  97. ;*****                                                                 *****
  98. ;*****                     T I M E R . A S M                           *****
  99. ;*****                                                                 *****
  100. ;*****                                                                 *****
  101. ;***** PROCEDURES                                                      *****
  102. ;*****                                                                 *****
  103. ;*****                                                                 *****
  104. ;*****                                                                 *****
  105. ;***** VARIABLES                                                       *****
  106. ;*****                                                                 *****
  107. ;*****                                                                 *****
  108. ;***** CONSTANTS                                                       *****
  109. ;*****                                                                 *****
  110. ;*****                                                                 *****
  111. ;***************************************************************************
  112. ;***************************************************************************
  113.  
  114. .386
  115.  
  116. ;************************************************************************
  117. ;**************** FLAT MODEL DATA SEGMENT STUFF *************************
  118. ;************************************************************************
  119.  
  120. _DATA   SEGMENT BYTE PUBLIC USE32 'DATA'
  121.  
  122. rcsid    db    "$Id: timer.asm 1.28 1995/02/15 01:36:56 matt Exp $"
  123.  
  124. TDATA           EQU     40h
  125. TCOMMAND        EQU     43h
  126. PIC             EQU     020h
  127. STACK_SIZE    EQU    4096    ; A 4K stack
  128.  
  129. TIMER_DATA STRUCT   
  130.     in_timer    db  0
  131.  
  132.     nested_counter    dd    0
  133.  
  134.     _timer_cnt      dd  65536
  135.     dos_timer       dd  ?
  136.  
  137.     joystick_poller    dd  0
  138.  
  139.     user_function   df  0
  140.     
  141.     org_interrupt    df  0    
  142.  
  143.     saved_stack    df  0
  144.  
  145.     new_stack    df  0
  146.  
  147.     tick_count    dd  0
  148.  
  149.     Installed db     0
  150.  
  151.     TimerStack    db  STACK_SIZE dup (?)        
  152. TIMER_DATA ENDS
  153.  
  154.     TimerData    TIMER_DATA <>    
  155.  
  156. _DATA   ENDS
  157.  
  158. DGROUP  GROUP _DATA
  159.  
  160.  
  161. ;************************************************************************
  162. ;**************** FLAT MODEL CODE SEGMENT STUFF *************************
  163. ;************************************************************************
  164.  
  165. _TEXT   SEGMENT BYTE PUBLIC USE32 'CODE'
  166.  
  167.         ASSUME  ds:_DATA
  168.         ASSUME  cs:_TEXT
  169.  
  170. INCLUDE PSMACROS.INC
  171.  
  172. TIMER_LOCKED_CODE_START:
  173.  
  174.         extn atexit_
  175.  
  176. PUBLIC timer_get_stamp64
  177.  
  178. timer_get_stamp64:
  179.         ; Return a 64-bit stamp that is the number of 1.19Mhz pulses
  180.         ; since the time was initialized.  Returns in EDX:EAX.
  181.         ; Also, interrupts must be disabled.
  182.  
  183.         xor     eax, eax            ; Clear all of EAX
  184.         out     TCOMMAND, al        ; Tell timer to latch
  185.  
  186.         mov     al, 0ah             ; Find if interrupt pending
  187.         out     PIC, al
  188.         jmp    @f
  189. @@:        in      al, PIC
  190.         and     eax, 01b
  191.         jz      NoInterrupt
  192.  
  193.         in      al, TDATA           ; Read in lo byte
  194.         mov     dl, al
  195.             in      al, TDATA           ; Read in hi byte
  196.         mov    dh, al
  197.         and    edx, 0ffffh
  198.         mov    eax, TimerData._timer_cnt
  199.         shl    eax, 1        
  200.         sub    eax, edx
  201.             
  202.         push    ebx
  203.         mov    ebx, eax
  204.         mov    eax, TimerData.tick_count
  205.         imul    TimerData._timer_cnt    ; edx:eax = Number of 1.19 MHz ticks elapsed...
  206.         add    eax, ebx
  207.         adc    edx, 0                
  208.         pop    ebx
  209.  
  210.         ret
  211.  
  212. NoInterrupt:
  213.         in      al, TDATA           ; Read in lo byte
  214.         mov     ah, al
  215.         in      al, TDATA           ; Read in hi byte
  216.         xchg    ah, al              ; arrange em correctly
  217.         mov     edx, TimerData._timer_cnt
  218.         sub     dx, ax              ; BX = timer ticks
  219.         mov     ax, dx
  220.  
  221.         push    ebx
  222.         mov    ebx, eax
  223.         mov    eax, TimerData.tick_count
  224.         imul    TimerData._timer_cnt    ; edx:eax = Number of 1.19 MHz ticks elapsed...
  225.         add    eax, ebx
  226.         adc    edx, 0                
  227.         pop    ebx
  228.  
  229.         ret
  230.  
  231.  
  232. PUBLIC  timer_get_fixed_seconds_
  233.  
  234. timer_get_fixed_seconds_:
  235.         push    ebx
  236.         push    edx
  237.  
  238.         cli
  239.         call    timer_get_stamp64
  240.         sti
  241.  
  242.         ; Timing in fixed point (16.16) seconds.
  243.         ; Can be used for up to 1000 hours
  244.         shld    edx, eax, 16            ; Keep 32+11 bits
  245.         shl     eax, 16            
  246.         ; edx:eax = number of 1.19Mhz pulses elapsed.
  247.         mov     ebx, 1193180
  248.  
  249. ; Make sure we won't divide overflow.  Make time wrap at about 9 hours
  250. sub_again:        sub     edx, ebx    ; subtract until negative...
  251.         jns     sub_again    ; ...to prevent divide overflow...
  252.         add     edx, ebx    ; ...then add in to get correct value.
  253.         div     ebx
  254.         ; eax = fixed point seconds elapsed...
  255.  
  256.         pop     edx
  257.         pop     ebx
  258.  
  259.         ret
  260.  
  261. PUBLIC  timer_get_fixed_secondsX_
  262.  
  263. timer_get_fixed_secondsX_:
  264.         push    ebx
  265.         push    edx
  266.  
  267.         call    timer_get_stamp64
  268.  
  269.         ; Timing in fixed point (16.16) seconds.
  270.         ; Can be used for up to 1000 hours
  271.         shld    edx, eax, 16            ; Keep 32+11 bits
  272.         shl     eax, 16            
  273.         ; edx:eax = number of 1.19Mhz pulses elapsed.
  274.         mov     ebx, 1193180
  275.  
  276. xsub_again:        sub     edx, ebx    ; subtract until negative...
  277.         jns     xsub_again    ; ...to prevent divide overflow...
  278.         add     edx, ebx    ; ...then add in to get correct value.
  279.  
  280.         div     ebx
  281.         ; eax = fixed point seconds elapsed...
  282.  
  283.         pop     edx
  284.         pop     ebx
  285.  
  286.         ret
  287.  
  288. PUBLIC timer_get_approx_seconds_
  289. timer_get_approx_seconds_:
  290.     push    ebx
  291.     push    edx
  292.  
  293.     mov    eax, TimerData.tick_count
  294.     imul    TimerData._timer_cnt    ; edx:eax = Number of 1.19 MHz ticks elapsed...
  295.     shld    edx, eax, 16            ; Keep 32+16 bits, for conversion to fixed point
  296.     shl     eax, 16            
  297.     ; edx:eax = number of 1.19Mhz pulses elapsed.
  298.     mov     ebx, 1193180
  299.  
  300. approx_sub_again:    sub     edx, ebx    ; subtract until negative...
  301.     jns     approx_sub_again    ; ...to prevent divide overflow...
  302.     add     edx, ebx    ; ...then add in to get correct value.
  303.  
  304.     div     ebx
  305.     ; eax = fixed point seconds elapsed...
  306.  
  307.     pop    edx
  308.     pop    ebx
  309.     ret
  310.  
  311.  
  312.  
  313. ;extern void timer_set_rate(int count_val);
  314. ;extern void timer_set_function( void _far * function );
  315.  
  316. PUBLIC  timer_set_rate_
  317. timer_set_rate_:
  318.     ; eax = rate
  319.     pushad
  320.  
  321.     ; Make sure eax below or equal to 65535 and above 0
  322.     ; if its not, make it be 65536 which is normal dos
  323.     ; timing.
  324.     cmp    eax, 65535
  325.     jbe    @f
  326.     mov    eax, 65536
  327. @@:    cmp    eax, 0
  328.     jne    @f
  329.     mov    eax, 65536
  330. @@:    ; Set the timer rate to eax
  331.     cli
  332.     mov    TimerData.tick_count, 0
  333.     mov     TimerData._timer_cnt, eax        
  334.     mov     al, 34h        ; count in binary, mode 2, load low byte then hi byte, counter 0:  00 11 010 0
  335.     out     TCOMMAND, al    ; Reset PIT channel 0
  336.     mov     eax, TimerData._timer_cnt
  337.     out     TDATA, al
  338.     mov     al, ah
  339.     out     TDATA, al
  340.     sti
  341.     popad
  342.     ret
  343.  
  344. PUBLIC  timer_set_function_
  345. timer_set_function_:
  346.     ; dx:eax = far pointer to user function
  347.     pushad
  348.     cli
  349.     mov    dword ptr TimerData.user_function[0], eax    ; offset
  350.     mov     word ptr TimerData.user_function[4], dx        ; selector
  351.     sti
  352.     popad
  353.     ret
  354.  
  355. PUBLIC timer_set_joyhandler_
  356. timer_set_joyhandler_:
  357.     cli
  358.     mov    TimerData.joystick_poller, eax
  359.     sti
  360.     ret
  361.  
  362.  
  363. ;************************************************************************
  364. ;************************************************************************
  365. ;*****                                                              *****
  366. ;*****                T I M E R _ H A N D L E R                     *****
  367. ;*****                                                              *****
  368. ;************************************************************************
  369. ;************************************************************************
  370.  
  371. timer_handler:
  372.         push    ds
  373.         push    es
  374.         push    eax
  375.  
  376.         mov     ax, DGROUP       ; Interrupt, so point to our data segment
  377.         mov     ds, ax
  378.         mov     es, ax
  379.  
  380.         ; Increment time counter...
  381.         inc    TimerData.tick_count
  382.  
  383.         mov    eax, TimerData._timer_cnt
  384.         add     TimerData.dos_timer, eax        ; Increment DOS timer
  385.         cmp    TimerData.dos_timer, 65536
  386.         jb    NoChainToOld            ; See if we need to chain to DOS 18.2
  387.         and    TimerData.dos_timer, 0ffffh
  388.  
  389.         ;
  390.         ; Call the original DOS handler....
  391.         ;
  392.         pushfd
  393.         call    fword ptr [TimerData.org_interrupt]
  394.  
  395.         jmp    NoReset        ;old handler has reset, so we don't
  396.  
  397. NoChainToOld:
  398.         ; Reset controller
  399.         mov     al, 20h         ; Reset interrupt controller
  400.         out     20h, al
  401.  
  402. NoReset:
  403.         cmp    TimerData.in_timer, 0
  404.         jne    ExitInterrupt
  405.  
  406.         mov    TimerData.in_timer, 1        ; Mark that we're in a timer interrupt...
  407.  
  408.         ; Reenable interrupts
  409.         sti            ; Reenable interrupts
  410.  
  411.         cmp     word ptr TimerData.user_function[4], 0        ; Check the selector...
  412.         je      NoUserFunction
  413.  
  414.         ; Switch stacks while calling the user-definable function...
  415.         pushad
  416.         push    fs
  417.         push    gs
  418.         mov    dword ptr TimerData.saved_stack[0], esp
  419.         mov    word ptr TimerData.saved_stack[4], ss
  420.         lss    esp, TimerData.new_stack    ; Switch to new stack
  421.         call    fword ptr [TimerData.user_function]    ; Call new function
  422.         lss    esp,  TimerData.saved_stack    ; Switch back to original stack
  423.         pop    gs
  424.         pop    fs
  425.         popad
  426.  
  427. NoUserFunction:    
  428.         cmp    dword ptr TimerData.joystick_poller, 0
  429.         je    NoJoyPolling
  430.         mov    eax, TimerData._timer_cnt
  431.         mov    dword ptr TimerData.saved_stack[0], esp
  432.         mov    word ptr TimerData.saved_stack[4], ss
  433.         lss    esp, TimerData.new_stack    ; Switch to new stack
  434.         call    dword ptr TimerData.joystick_poller
  435.         lss    esp,  TimerData.saved_stack    ; Switch back to original stack
  436.  
  437. NoJoyPolling:
  438.         cli
  439.         mov    TimerData.in_timer, 0
  440.  
  441. ExitInterrupt:
  442.         ;;mov     al, 20h         ; Reset interrupt controller
  443.         ;;out     20h, al
  444.         pop    eax
  445.         pop    es
  446.         pop    ds
  447.         iretd                ; Return from timer interrupt
  448.  
  449.  
  450. TIMER_LOCKED_CODE_STOP:
  451.  
  452. ;************************************************************************
  453. ;************************************************************************
  454. ;*****                                                              *****
  455. ;*****                   T I M E R _ I N I T                        *****
  456. ;*****                                                              *****
  457. ;************************************************************************
  458. ;************************************************************************
  459.  
  460.  
  461. PUBLIC  timer_init_
  462.  
  463. timer_init_:
  464.         pushad
  465.         push    ds
  466.         push    es
  467.  
  468.         cmp     TimerData.Installed, 1
  469.         je      AlreadyInstalled
  470.  
  471.         mov     TimerData._timer_cnt, 65536    ; Set to BIOS's normal 18.2 Hz
  472.         mov     TimerData.dos_timer, 0        ; clear DOS Interrupt counter
  473.         mov     dword ptr TimerData.user_function[0], 0    ; offset of user function
  474.         mov     word ptr TimerData.user_function[4], 0    ; selector of user function
  475.  
  476.         lea    eax, ds:[TimerData.TimerStack]    ; Use EAX as temp stack pointer
  477.         add    eax, STACK_SIZE            ; Top of stack minus space for saving old ss:esp
  478.         mov    dword ptr TimerData.new_stack[0], eax
  479.         mov    word ptr TimerData.new_stack[4], ds
  480.  
  481.         ;--------------- lock data used in interrupt
  482.         mov    eax, SIZEOF TIMER_DATA
  483.         mov    esi, eax
  484.         shr    esi, 16            
  485.         mov    edi, eax
  486.         and    edi, 0ffffh    ; si:di = length of region to lock in bytes
  487.         lea    ebx, ds:TimerData
  488.         lea    ecx, ds:TimerData
  489.         shr    ebx, 16
  490.         and    ecx, 0ffffh    ; bx:cx = start of linear address to lock
  491.         mov    eax, 0600h    ; DPMI lock address function
  492.         int    31h        ; call dpmi
  493.         jnc    @f
  494.         int    3        ; LOCK FAILED!!
  495. @@:
  496.         ;--------------- lock code used in interrupt
  497.         lea    eax, cs:TIMER_LOCKED_CODE_STOP
  498.         lea    ecx, cs:TIMER_LOCKED_CODE_START
  499.         sub    eax, ecx
  500.         inc    eax        ; EAX = size of timer interrupt handler
  501.         mov    esi, eax
  502.         shr    esi, 16            
  503.         mov    edi, eax
  504.         and    edi, 0ffffh    ; si:di = length of region to lock in bytes
  505.         lea    ebx, cs:TIMER_LOCKED_CODE_START
  506.         lea    ecx, cs:TIMER_LOCKED_CODE_START
  507.         shr    ebx, 16
  508.         and    ecx, 0ffffh    ; bx:cx = start of linear address to lock
  509.         mov    eax, 0600h    ; DPMI lock address function
  510.         int    31h        ; call dpmi
  511.         jnc    @f
  512.         int    3        ; LOCK FAILED!!
  513. @@:
  514.  
  515.         ;**************************************************************
  516.         ;******************* SAVE OLD INT8 HANDLER ********************
  517.         ;**************************************************************
  518.         mov     eax, 03508h             ; DOS Get Vector 08h
  519.         int     21h                     ; Call DOS
  520.  
  521.         mov     dword ptr TimerData.org_interrupt[0], ebx    ; offset of user function
  522.         mov    word ptr TimerData.org_interrupt[4], es        ; selector of user function
  523.  
  524.         ;**************************************************************
  525.         ;***************** INSTALL NEW INT8 HANDLER *******************
  526.         ;**************************************************************
  527.  
  528.         cli
  529.  
  530.         mov     al, 34h        ; count in binary, mode 2, load low byte then hi byte, counter 0:  00 11 010 0
  531.         out     TCOMMAND, al    ; Reset PIT channel 0
  532.         mov     eax, TimerData._timer_cnt
  533.         out     TDATA, al
  534.         mov     al, ah
  535.         out     TDATA, al
  536.  
  537.         mov     TimerData.tick_count, 0
  538.         mov     TimerData.Installed,1
  539.  
  540.         mov     eax, 02508h             ; DOS Set Vector 08h
  541.         mov     edx, offset timer_handler  ; Point DS:EDX to new handler
  542.         mov     bx, cs
  543.         push    ds
  544.         mov     ds, bx
  545.         int     21h
  546.         pop     ds
  547.         sti
  548.         lea     eax, cs:timer_close_
  549.         call    atexit_
  550.  
  551. AlreadyInstalled:
  552.  
  553.         pop     es
  554.         pop     ds
  555.         popad
  556.  
  557.         ret
  558.  
  559.  
  560. ;************************************************************************
  561. ;************************************************************************
  562. ;*****                                                              *****
  563. ;*****                  T I M E R _ C L O S E _                     *****
  564. ;*****                                                              *****
  565. ;************************************************************************
  566. ;************************************************************************
  567.  
  568. PUBLIC  timer_close_
  569.  
  570. timer_close_:
  571.         push    eax
  572.         push    edx
  573.         push    ds
  574.  
  575.  
  576.         cmp     TimerData.Installed, 0
  577.         je      NotInstalled
  578.         mov     TimerData.Installed, 0
  579.  
  580.         ;**************************************************************
  581.         ;***************** RESTORE OLD INT9 HANDLER *******************
  582.         ;**************************************************************
  583.  
  584.         cli
  585.         mov     al, 36h        ; count in binary, mode 3, load low byte then hi byte, counter 0:  00 11 011 0
  586.         out     TCOMMAND, al    ; Reser PIT channel 0
  587.         mov     ax, 0h
  588.         out     TDATA, al
  589.         mov     al, ah
  590.         out     TDATA, al
  591.  
  592.         push    ds
  593.         mov     eax, 02508h         ; DOS Set Vector 08h
  594.         mov     edx, dword ptr TimerData.org_interrupt[0]
  595.         mov     ds, word ptr TimerData.org_interrupt[4]
  596.         int     21h
  597.         pop    ds
  598.  
  599.         sti
  600.         
  601.         cmp    TimerData.nested_counter, 0
  602.         je    NoNestedInterrupts
  603.         mov    eax, TimerData.nested_counter
  604.         ;int     3        ; Get John!!
  605.     
  606. NoNestedInterrupts:
  607.         
  608.  
  609. NotInstalled:
  610.         pop     ds
  611.         pop     edx
  612.         pop     eax
  613.  
  614.         ret
  615.  
  616.  
  617. _TEXT           ENDS
  618.  
  619.  
  620.         END
  621.