home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / DOOG / CTASK.ZIP / TSKTIM.ASM < prev    next >
Assembly Source File  |  1989-12-20  |  10KB  |  498 lines

  1. ;
  2. ;    --- Version 2.0 89-12-13 17:34 ---
  3. ;
  4. ;    CTask - Timer interrupt handler (IBM specific)
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Patschkauer Weg 31
  9. ;        D-1000 Berlin 33
  10. ;        West Germany
  11. ;
  12. ;    NOTE: Logic in this module has been changed to accommodate two
  13. ;          different ways to handle chaining to the original INT 8
  14. ;          entry in version 1.2.
  15. ;
  16.     name    tsktim
  17.     .model    large,c
  18. ;
  19.     public    tsk_install_timer
  20.     public    tsk_remove_timer
  21.     public    tsk_chain_timer
  22. ;
  23.     include    tsk.mac
  24. ;
  25.     extrn    tsk_dgroup: word
  26.     extrn    sched_int: far
  27.     extrn    inc_counter: far
  28. ;
  29. STACKSIZE    =    128    ; local stack size (words)
  30. ;
  31. timer    equ    40h            ; 8253 timer base I/O address
  32. inta00    equ    20h            ; 8259 int controller base
  33. eoi    equ    20h            ; unspecific EOI
  34. ;
  35. intseg    segment at 0
  36. ;
  37.         org    8*4
  38. tintofs        dw    ?        ; timer interrupt entry
  39. tintseg        dw    ?
  40.  
  41. intseg    ends
  42. ;
  43. ;
  44.     .tsk_data
  45. ;
  46.     extrn    tsk_glob_rec: byte
  47.     extrn    tsk_timer_counter:word
  48.     extrn    tsk_int8_counter:word
  49.     extrn    tsk_instflags: word
  50. ;
  51. divisor        dw    ?
  52. timflag        dw    ?
  53. timcnt        dw    ?
  54. sys_ticks    dw    ?
  55. ;
  56.     dw    STACKSIZE dup(?)
  57. local_stack    label    word
  58. ;
  59.     .tsk_edata
  60.     .tsk_code
  61. ;
  62. timer_save    label    dword        ; in CSEG to allow addressing
  63. tsofs        dw    ?
  64. tsseg        dw    ?
  65. ;
  66. r_ss        dw    ?
  67. r_sp        dw    ?
  68. in_timer    db    0
  69. ;
  70. ;----------------------------------------------------------------------
  71. ;
  72. ;    Timer interrupt handler, late INT 8 processing
  73. ;
  74. ;    Normal timer tick. The tick counter is incremented, and
  75. ;    the interrupt controller is checked for other pending interrupts.
  76. ;    If the timer tick occurred during processing of another interrupt,
  77. ;    we may not call the scheduler, since this would delay the
  78. ;    interrupt handler.
  79. ;
  80. ;    Note that an EOI is issued here to allow interrupts to occur
  81. ;    during further processing. The original INT 8 handler will be
  82. ;    chained to from a special task. The reason behind this is that
  83. ;    some TSR's link into the timer interrupt and may do some lengthy
  84. ;    processing there. To allow the TSR to be preempted, we must use
  85. ;    a task for the INT 8 processing.
  86. ;
  87. timer_int_late    proc    far
  88. ;
  89. ;    first, check for overrun. If we're already processing a tick,
  90. ;    we simply ignore this one. That's not that great a way to
  91. ;    react, but anything else would easily mess things up, and we're
  92. ;    already in trouble anyway if this should happen.
  93. ;
  94.     cmp    cs:in_timer,0
  95.     je    timer_ok
  96.     push    ax
  97.     mov    al,eoi            ; issue EOI
  98.     out    inta00,al
  99.     pop    ax
  100.     iret
  101. ;
  102. ;    Not a second interrupt, continue processing. First, set the
  103. ;    in_timer marker, and switch to our local stack.
  104. ;
  105. timer_ok:
  106.     inc    cs:in_timer
  107.     mov    cs:r_ss,ss
  108.     mov    cs:r_sp,sp
  109.     mov    ss,cs:tsk_dgroup
  110.     mov    sp,offset local_stack
  111.     sti
  112.     cld
  113.     push    ax
  114.     push    ds
  115.     mov    ds,cs:tsk_dgroup
  116. ;
  117. norm_tick:
  118. ;
  119.     push    es            ; save other regs
  120.     push    bx
  121.     push    cx
  122.     push    dx
  123.     push    si
  124.     push    di
  125.     push    bp
  126.     mov    ax,ds
  127.     mov    es,ax
  128.     mov    ax,offset tsk_timer_counter
  129.     push    ds
  130.     push    ax
  131.     call    inc_counter        ; increase timer tick counter
  132.     add    sp,4
  133. ;
  134. ;    Now the timer counter is decremented. If it is zero,
  135. ;    we must chain to the original INT 8, so the counter for
  136. ;    the chain task is incremented.
  137. ;
  138.     dec    timcnt            ; decrement tick count
  139.     jnz    no_pass            ; pass on this int if zero
  140. ;
  141.     mov    ax,sys_ticks
  142.     mov    timcnt,ax        ; re-init tick counter
  143. ;
  144.     mov    ax,offset tsk_int8_counter
  145.     push    ds
  146.     push    ax
  147.     call    inc_counter        ; increase timer tick counter
  148.     add    sp,4
  149. ;
  150. ;    Now we decrement all installed tick counters 
  151. ;
  152. no_pass:
  153.     les    bx,tsk_glob_rec.ticker_chain
  154. ;
  155. count_dec:
  156.     mov    ax,es
  157.     or    ax,bx
  158.     jz    tick_ready
  159.     mov    ax,es:ticklo[bx]
  160.     or    ax,es:tickhi[bx]
  161.     jz    count_next
  162.     sub    es:ticklo[bx],1
  163.     sbb    es:tickhi[bx],0
  164. count_next:
  165.     les    bx,es:ticknext[bx]
  166.     jmp    count_dec
  167. ;
  168. tick_ready:
  169.     pop    bp
  170.     pop    di
  171.     pop    si
  172.     pop    dx
  173.     pop    cx
  174.     pop    bx
  175.     pop    es
  176. ;
  177.     cli
  178.     mov    al,eoi            ; issue EOI
  179.     out    inta00,al
  180.     mov    al,0bh            ; access int control reg
  181.     out    inta00,al
  182.     in    al,inta00        ; ints pending?
  183.     or    al,al
  184.     jnz    tim_retn        ; don't schedule if other ints active
  185.     pop    ds
  186.     pop    ax
  187.     mov    ss,cs:r_ss
  188.     mov    sp,cs:r_sp
  189.     dec    cs:in_timer
  190.     jmp    sched_int        ; else schedule
  191. ;
  192. tim_retn:
  193.     pop    ds
  194.     pop    ax
  195.     mov    ss,cs:r_ss
  196.     mov    sp,cs:r_sp
  197.     dec    cs:in_timer
  198.     iret
  199. ;
  200. timer_int_late    endp
  201. ;
  202. ;----------------------------------------------------------------------
  203. ;
  204. ;    Timer interrupt handler, early INT 8 processing
  205. ;
  206. ;    With this interrupt handler, the original INT 8 is chained to
  207. ;    directly, before calling the scheduler.
  208. ;
  209. ;    This avoids compatibility problems with TSR's that do strange
  210. ;    things in the timer tick, but it may lead to problems within
  211. ;    CTask, should the strange TSR decide to loop in the INT 8 handler,
  212. ;    or even to never return. Oh well, you can't please all TSR's all
  213. ;    of the time...
  214. ;
  215. timer_int_early    proc    far
  216. ;
  217.     cld
  218.     push    ax
  219.     push    ds
  220.     mov    ds,cs:tsk_dgroup
  221. ;
  222. ;    The timer counter is decremented. If it is zero,
  223. ;    we chain directly to the original INT 8.
  224. ;    Since the local stack is not yet in use, 
  225. ;    multiple entries into this part are possible.
  226. ;
  227.     dec    timcnt            ; decrement tick count
  228.     jnz    eno_pass
  229. ;
  230.     mov    ax,sys_ticks
  231.     mov    timcnt,ax        ; re-init tick counter
  232. ;
  233.     pop    ds
  234.     pop    ax
  235.     pushf
  236.     call    cs:timer_save        ; call original INT 8
  237.     cli
  238.     push    ax
  239.     push    ds
  240.     mov    ds,cs:tsk_dgroup
  241.     jmp    short e_pass
  242. ;
  243. ;    On return from INT 8 processing, or when INT 8 was not chained,
  244. ;    processing is pretty much the same as in timer_int_late.
  245. ;
  246. eno_pass:
  247.     mov    al,eoi            ; issue EOI when not chained
  248.     out    inta00,al
  249. ;
  250. e_pass:
  251.     cmp    cs:in_timer,0
  252.     je    etimer_ok
  253.     pop    ds
  254.     pop    ax
  255.     iret
  256. ;
  257. etimer_ok:
  258.     inc    cs:in_timer
  259.     mov    cs:r_ss,ss
  260.     mov    cs:r_sp,sp
  261.     mov    ss,cs:tsk_dgroup
  262.     mov    sp,offset local_stack
  263.     sti
  264.     cld
  265. ;
  266.     push    es            ; save other regs
  267.     push    bx
  268.     push    cx
  269.     push    dx
  270.     push    si
  271.     push    di
  272.     push    bp
  273.     mov    ax,ds
  274.     mov    es,ax
  275.     mov    ax,offset tsk_timer_counter
  276.     push    ds
  277.     push    ax
  278.     call    inc_counter        ; increase timer tick counter
  279.     add    sp,4
  280. ;
  281. ;    Now we decrement all installed tick counters 
  282. ;
  283.     les    bx,tsk_glob_rec.ticker_chain
  284. ;
  285. ecount_dec:
  286.     mov    ax,es
  287.     or    ax,bx
  288.     jz    etick_ready
  289.     mov    ax,es:ticklo[bx]
  290.     or    ax,es:tickhi[bx]
  291.     jz    ecount_next
  292.     sub    es:ticklo[bx],1
  293.     sbb    es:tickhi[bx],0
  294. ecount_next:
  295.     les    bx,es:ticknext[bx]
  296.     jmp    ecount_dec
  297. ;
  298. etick_ready:
  299.     pop    bp
  300.     pop    di
  301.     pop    si
  302.     pop    dx
  303.     pop    cx
  304.     pop    bx
  305.     pop    es
  306. ;
  307.     cli
  308.     mov    al,0bh            ; access int control reg
  309.     out    inta00,al
  310.     in    al,inta00        ; ints pending?
  311.     or    al,al
  312.     jnz    etim_retn        ; don't schedule if other ints active
  313.     mov    ss,cs:r_ss
  314.     mov    sp,cs:r_sp
  315.     pop    ds
  316.     pop    ax
  317.     dec    cs:in_timer
  318.     jmp    sched_int        ; else schedule
  319. ;
  320. etim_retn:
  321.     mov    ss,cs:r_ss
  322.     mov    sp,cs:r_sp
  323.     pop    ds
  324.     pop    ax
  325.     dec    cs:in_timer
  326.     iret
  327. ;
  328. timer_int_early    endp
  329. ;
  330. ;---------------------------------------------------------------------
  331. ;
  332. ;    Install timer.
  333. ;    The scheduler is not called on this first tick.
  334. ;
  335. tim_install    proc    far
  336. ;
  337.     push    ax
  338.     push    ds
  339.     push    es
  340. ;
  341.     mov    ds,cs:tsk_dgroup
  342. ;
  343.     mov    timflag,0        ; signal init ready
  344.     mov    ax,sys_ticks
  345.     mov    timcnt,ax        ; init tick counter
  346.     mov    al,36h
  347.     out    timer+3,al        ; setup to load divisor
  348.     mov    al,byte ptr divisor
  349.     out    timer,al        ; lsb
  350.     mov    al,byte ptr divisor+1
  351.     out    timer,al        ; msb
  352. ;
  353.     xor    ax,ax
  354.     mov    es,ax
  355.     assume    es:intseg
  356.     mov    ax,offset timer_int_late
  357.     test    tsk_instflags,IFL_INT8_DIR
  358.     jz    tim_inst_1
  359.     mov    ax,offset timer_int_early
  360. ;
  361. tim_inst_1:
  362.     mov    es:tintofs,ax
  363.     mov    es:tintseg,cs
  364. ;
  365.     pop    es
  366.     pop    ds
  367.     pop    ax
  368.     jmp    cs:timer_save
  369. ;
  370. tim_install    endp
  371. ;
  372. ;------------------------------------------------------------------------
  373. ;
  374. ;       Un-Install timer (wait until system tick count reached).
  375. ;    The scheduler is not called while waiting for the tick count.
  376. ;
  377. tim_uninstall    proc    far
  378. ;
  379.     push    ax
  380.     push    ds
  381. ;
  382.     mov    ds,cs:tsk_dgroup
  383. ;
  384.     cli
  385.     dec    timcnt            ; decrement tick count
  386.     jz    uninit            ; go un-install if zero
  387.     mov    al,eoi            ; else just issue EOI
  388.     out    inta00,al
  389.     pop    ds
  390.     pop    ax
  391.     iret
  392. ;
  393. ;    Uninstall timer int handler
  394. ;
  395. uninit:
  396.     mov    timflag,0        ; mark un-install complete
  397.     mov    al,36h            ; setup to load divisor
  398.     out    timer+3,al
  399.     mov    al,0            ; divisor 0 means 65536
  400.     out    timer,al        ; lsb
  401.     out    timer,al        ; msb
  402. ;
  403.     push    es
  404.     xor    ax,ax
  405.     mov    es,ax
  406.     assume    es:intseg
  407.     mov    ax,cs:tsofs        ; restore vector
  408.     mov    tintofs,ax
  409.     mov    ax,cs:tsseg
  410.     mov    tintseg,ax
  411.     pop    es
  412.     pop    ds
  413.     pop    ax
  414.     jmp    cs:timer_save        ; pass on interrupt
  415. ;
  416. tim_uninstall    endp
  417. ;
  418. ;----------------------------------------------------------------------
  419. ;
  420. ;    void far tsk_chain_timer (void)
  421. ;
  422. ;       Pass timer tick on to interrupt 8 chain.
  423. ;
  424. tsk_chain_timer    proc    near
  425. ;
  426.     pushf
  427.     cli
  428.     call    cs:timer_save
  429.     ret
  430. ;
  431. tsk_chain_timer    endp
  432. ;
  433. ;
  434. ;    void near tsk_install_timer (word divisor, word sys_ticks)
  435. ;
  436. ;    This routine installs the timer tick int handler.
  437. ;    The timer chip is reprogrammed on the next tick.
  438. ;
  439. tsk_install_timer    proc    near uses ds, pdivisor: word, psysticks: word
  440. ;
  441.     mov    ds,cs:tsk_dgroup
  442.     mov    ax,pdivisor
  443.     mov    divisor,ax
  444.     mov    ax,psysticks
  445.     mov    sys_ticks,ax
  446.     mov    timflag,1        ; set init-flag
  447.     xor    ax,ax
  448.     mov    es,ax            ; establish addressing for intseg
  449.     assume    es:intseg
  450. ;
  451.     mov    ax,tintofs        ; save old timer int addr
  452.     mov    tsofs,ax
  453.     mov    ax,tintseg
  454.     mov    tsseg,ax
  455.     cli
  456.     mov    tintofs,offset tim_install ; set new timer int addr
  457.     mov    tintseg,cs
  458.     sti
  459.     assume    es:nothing
  460. wait_set:
  461.     cmp    timflag,0        ; wait until timer started
  462.     jne    wait_set
  463.     ret
  464. ;
  465. tsk_install_timer    endp
  466. ;
  467. ;
  468. ;    void far tsk_remove_timer (void)
  469. ;
  470. ;    This routine un-installs the timer tick int handler.
  471. ;    The timer chip is reprogrammed & the interrupt vector
  472. ;    restored when the system tick count reaches zero.
  473. ;
  474. tsk_remove_timer    proc    near uses ds
  475. ;
  476.     mov    ds,cs:tsk_dgroup
  477.     mov    timflag,2        ; set un-init flag for timer
  478.  
  479.     xor    ax,ax
  480.     mov    es,ax            ; establish addressing for intseg
  481.     assume    es:intseg
  482. ;
  483.     cli
  484.     mov    tintofs,offset tim_uninstall ; set new timer int addr
  485.     mov    tintseg,cs
  486.     sti
  487.     assume    es:nothing
  488. wait_tim:
  489.         sti                             ; just to be safe
  490.     cmp    timflag,0        ; wait until int un-installed
  491.     jne    wait_tim
  492.     ret
  493. ;
  494. tsk_remove_timer    endp
  495. ;
  496.     end
  497.  
  498.