home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / c / playadlb / timer.asm < prev    next >
Encoding:
Assembly Source File  |  1991-03-26  |  6.3 KB  |  387 lines

  1. ;
  2. ; 08h interrupt driver (from BYTE special issue, nov. 86, pp 249-262)
  3. ;
  4. ; Adaptation: Marc Savary, Ad Lib Inc, 1986/11/03
  5. ;
  6.  
  7. ;    This module allows you to change the timer-0 interrupt rate,
  8. ;   without affecting the rate at which the currently installed
  9. ;   routine is called ( 18.2 Hz).
  10. ;
  11. ;    A user function (TimeOut()) is called after 'n'
  12. ;   interrupts, 'n' being reset after each call.
  13.  
  14.  
  15. ; Originally written for Lattice C Compiler, small model.  Adapted to
  16. ; Microsoft by using macros (notably BEGIN, P_END, EXTERN).  A flag for the
  17. ; type of compiler is defined in the file VERSION.INC.  According to this
  18. ; flag, the file containing the appropriate equates and macros is then
  19. ; included.
  20.  
  21.   INCLUDE VERSION.INC      ;*** compilation flags are defined in this file ***
  22.  
  23.   IF MICROSOFT
  24.     INCLUDE CMICRO.MAC     ;memory model & equates for Microsoft environment
  25.         .MODEL MEDIUM
  26.   ELSE
  27.     INCLUDE DOS.MAC        ;memory model & equates for Lattice environment
  28.   ENDIF
  29.  
  30.   INCLUDE COMMON.MAC       ;macros common to both environments
  31.  
  32.  
  33. clk_int equ 08h     ; timer-0 interrupt vector number
  34.  
  35.  
  36. ; ============= vector structure ==========
  37.  
  38. vector    struc
  39. regip    dw    ?
  40. regcs    dw    ?
  41. vector    ends
  42.  
  43.  
  44. ; ========================= DATA SEGMENT ============================
  45.  
  46.     DSEG
  47.  
  48. int_stack_size        equ    512
  49.  
  50. the_stack         db    int_stack_size DUP ('S')
  51. interrupt_stack_top dw  0
  52.  
  53.     ENDDS
  54.         
  55.  
  56. ;========================== CODE SEGMENT ============================
  57.  
  58.   IF MICROSOFT
  59.     PSEG  <TIMER>
  60.   ELSE
  61.     PSEG
  62.   ENDIF
  63.  
  64.   EXTERN TimeOut
  65.  
  66.  
  67. clkdivh    dw    ?        ; actual divisor ... high
  68. clkdivl    dw    ?        ; ... low
  69. clkmod    dw    ?        ; divisor modulus
  70.  
  71. int08    vector    <>
  72.  
  73. appl_ds dw    ?
  74. old_ss    dw    ?        ; interrupted code's SS
  75. old_sp    dw    ?        ; SP .......
  76.  
  77. soundDelay    dw    ?    ; delay counter
  78. user_routine_on    db    (?)    ; flag to avoid reentrance
  79.  
  80.  
  81.  
  82.  
  83. ;    clkrate()
  84. ;
  85. ;    change timer-0 divider
  86. ;    IN : AX count divisor
  87. ;
  88.     IF    LPROG
  89. clkrate    proc FAR
  90.     ELSE
  91. clkrate    proc NEAR
  92.     ENDIF
  93. ; load counter 0 of 8253:
  94.     push    ax
  95.     mov    al, 00110110b    ; square wave mode
  96.     out    43h, al
  97.     pop    ax
  98.     out    40h, al
  99.     xchg    ah, al
  100.     out    40h, al
  101.     xchg    ah, al
  102.     ret
  103. clkrate endp
  104.  
  105.  
  106. ;   _SetInt( state)
  107. ;
  108. ;    enable/disable CPU interrupt.
  109. ;
  110. BEGIN  SetInt
  111.  
  112. Sintframe struc
  113.     dw    (?)
  114.     db    CPSIZE DUP (?)
  115. state    dw    (?)            ; interrupt state
  116. Sintframe ends
  117.     push    bp
  118.     mov    bp, sp
  119.  
  120.     cmp    [ bp].state, 0
  121.     jne    s_on
  122. ; off:
  123.     cli
  124.     jmp    s_end
  125. s_on:
  126.     sti
  127. s_end:
  128.     pop    bp
  129.     ret
  130.  
  131. P_END  SetInt
  132.  
  133.  
  134.  
  135.  
  136. ;   _SetClkRate( unsigned count)
  137. ;
  138. ;    Initialize interrupt rate to (1.119 MHz / count) cycles/sec.
  139. ;
  140. BEGIN SetClkRate
  141.  
  142. scrframe struc
  143.     dw    (?)
  144.     db    CPSIZE DUP (?)
  145. divid    dw    (?)            ; timer's divider
  146. scrframe ends
  147.     push    bp
  148.     mov    bp, sp
  149.  
  150.     mov    ax, [ bp].divid
  151.     pushf
  152.     cli    
  153.     mov    CS:clkdivl, ax
  154.     cmp    ax, 1
  155.     mov    CS:clkdivh, 0
  156.     adc    CS:clkdivh, 0
  157.     call    clkrate
  158.     popf
  159.     pop    bp
  160.     ret
  161. P_END  SetClkRate
  162.  
  163.  
  164.  
  165. ; Install clock-driver (soft int-08, timer-0).
  166. ; Save a copy of DS.
  167. ;
  168. BEGIN  clk_install
  169.  
  170. ; install clock interrupt handler
  171.     push    ax
  172.     push    dx
  173.  
  174. ; init. clk variables:
  175.     xor    ax, ax
  176.     call    clkrate
  177.     mov    CS:clkdivh, 1
  178.     mov    CS:clkdivl, ax
  179.     mov    CS:clkmod, ax
  180.  
  181. ; init flag:
  182.     mov    cs:user_routine_on, 0
  183.  
  184. ; save application DS:
  185.     mov    ax, ds
  186.     mov    cs:appl_ds, ax
  187.  
  188. ; save current int. vector
  189.     push    es
  190.     mov    ah, 35h
  191.     mov    al, clk_int
  192.     int    21h            ; get old vector
  193.     assume es:nothing
  194.     mov    CS:int08.regip, bx
  195.     mov    CS:int08.regcs, es
  196.     pop    es
  197. ; install interrupt intercept vector:
  198.     push    ds
  199.     mov    ah, 25h
  200.     mov    al, clk_int
  201.     mov    dx, offset clkint
  202.     mov    bx, CS
  203.     mov    ds, bx
  204.     int    21h            ; set int. vector
  205.     pop    ds
  206.     pop    dx
  207.     pop    ax
  208.  
  209.     ret
  210. P_END  clk_install
  211.  
  212.  
  213.  
  214. ;   _clk_uninstall()
  215. ;
  216. BEGIN  clk_uninstall
  217.  
  218.     xor    ax, ax
  219.     call    clkrate
  220. ; reset int. vector:
  221.     push    ds
  222.     mov    ah, 25h
  223.     mov    al, clk_int
  224.     lds    dx, CS:int08
  225.     int    21h            ; set vector ...
  226.     pop    ds
  227.     ret
  228. P_END  clk_uninstall
  229.  
  230.  
  231.  
  232.  
  233. ;   _StartTimeOut( delay)
  234. ;
  235. ;    Initialize count-down delay to 'delay'.
  236. ;
  237.  
  238. BEGIN  StartTimeOut
  239.  
  240. istad    struc
  241.     dw    (?)
  242.     db    CPSIZE DUP (?)
  243. delay    dw    (?)            ; delay before doing the next call
  244. istad    ends
  245.  
  246.     push    bp
  247.     mov    bp, sp
  248.     pushf
  249.     cli
  250.     mov     ax, [ bp].delay
  251.     mov     cs:soundDelay, ax
  252.     popf
  253.     pop    bp
  254.     ret
  255.  
  256. P_END  StartTimeOut
  257.  
  258.  
  259.  
  260. ;     clkint
  261. ;
  262. ; int-08 Interrupt Driver routine.
  263. ;
  264. ; Check for roll-over of 65536 cycles ( 18.2 hz ) and call
  265. ; old driver if so.
  266. ; Count-down delay variable, and if zero, call routine 'TimeOut()'
  267. ; & set the new delay.
  268. ;
  269. clkint    proc FAR
  270.  
  271.     push    ax
  272.  
  273. ; check for roll-over of 65536 cycles ( 18.2 hz )
  274.     mov    ax, CS:clkdivl
  275.     add    CS:clkmod, ax
  276.     mov    ax, CS:clkdivh
  277.     adc    ax, 0
  278.     jnz    clkint8
  279. ; not yet time, skip original interrupt
  280.     mov    al, 00100000b
  281.     out    20h, al            ; 8259 ...
  282.     jmp    clkint7
  283. ; do the original interrupt:
  284. clkint8    label    near
  285.     pushf
  286.     call    CS:int08
  287.  
  288. clkint7    label    near
  289.  
  290.     dec    CS:soundDelay        ; 16 bits unsigned counter
  291.     jnz    clkint_end
  292.  
  293. ; to avoid a reentrant call
  294.     cmp    CS:user_routine_on, 0
  295.     jnz    clkint_end        ; already active ...
  296.  
  297. ; end of delay. Prepare environment before calling TimeOut()
  298. ; (allocate temporary stack, set segment registers).
  299. ;
  300.  
  301. ; save all registers...    
  302.     push    bx
  303.     push    cx
  304.     push    dx
  305.     push    ds
  306.     push    es
  307.     push    si
  308.     push    di
  309.     push    bp
  310.  
  311. ; save active stack pointers
  312.     mov    cs:old_ss, ss
  313.     mov    cs:old_sp, sp
  314.  
  315. ; get application's DS
  316.     mov    ax, cs:appl_ds
  317.     mov    es, ax
  318.     mov    ds, ax
  319.  
  320. ; set new stack:
  321.     mov    ss, ax
  322.     mov    sp, offset DGROUP:interrupt_stack_top
  323.  
  324.  
  325. go_user    label near
  326. public go_user
  327.  
  328. ; protect call with flag
  329.     inc    CS:user_routine_on
  330.  
  331. ; call the C routine
  332.     sti
  333.     IF MICROSOFT
  334.     call    _TimeOut         ; time-out driver ... ==> AX: new delay
  335.     ELSE
  336.     call    TimeOut         ; time-out driver ... ==> AX: new delay
  337.     ENDIF
  338.  
  339.     cli
  340.     dec    CS:user_routine_on
  341.  
  342. ; compute new delay
  343.     mov    bx, CS:soundDelay
  344.     neg    bx                ; # of interrupt since call to TimeOut()
  345.     cmp    bx, ax                ; time-out ?
  346.     jb    clk_delay_ok            ; no ...
  347.  
  348. ; we must recall TimeOut immediately
  349.     mov    CS:soundDelay, 0
  350.     jmp    go_user
  351.  
  352. clk_delay_ok    label near
  353.     add    CS:soundDelay, ax        ; leftover delay count
  354.  
  355. ; restore stack
  356.     mov    bx, CS:old_ss
  357.     mov    ss, bx
  358.     mov    sp, CS:old_sp
  359.  
  360.     sti
  361.  
  362.     pop    bp
  363.     pop    di
  364.     pop    si
  365.     pop    es
  366.     pop    ds
  367.     pop    dx
  368.     pop    cx
  369.     pop    bx
  370.  
  371. clkint_end    label near
  372.     pop    ax
  373.     iret
  374. clkint    endp
  375.  
  376.  
  377.   IF MICROSOFT
  378.     ENDPS  <TIMER>
  379.   ELSE
  380.     ENDPS
  381.   ENDIF
  382.  
  383.     end
  384.  
  385.