home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / CTASK22.ZIP / TSKTIM.ASM < prev    next >
Assembly Source File  |  1990-10-12  |  14KB  |  665 lines

  1. ;
  2. ;    --- Version 2.2 90-10-12 10:46 ---
  3. ;
  4. ;    CTask - Timer interrupt handler (IBM specific)
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic Gmbh
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ;    NOTE: Logic in this module has been changed to accommodate two
  14. ;          different ways to handle chaining to the original INT 8
  15. ;          entry in version 1.2.
  16. ;
  17. ;    CAUTION: This module can only be installed in the primary kernel.
  18. ;         It is not ROMable.
  19. ;
  20. ;    For non-IBM applications, you have to completely replace
  21. ;    this module and write your own.
  22. ;    You should be able to use this module at least as a model
  23. ;    by throwing out about 80%, mainly the initialization 
  24. ;    and interrupt chaining stuff. All you really need is the
  25. ;    tsk_timer_counter increment, and the ticker processing,
  26. ;    which can be left unchanged. The section enclosed by
  27. ;    IF INT8_EARLY most likely is the one you should use as 
  28. ;    reference, since you will usuallly not have other routines 
  29. ;    chained to the timer tick in an embedded system.
  30. ;
  31.     name    tsktim
  32. ;
  33.     include    tsk.mac
  34.     include    tskdeb.h
  35. ;
  36.     .tsk_model
  37. ;
  38.     Pubfunc    tsk_install_timer
  39.     Pubfunc    tsk_remove_timer
  40.     IF    NOT INT8_EARLY
  41.     Pubfunc    tsk_chain_timer
  42.     ENDIF
  43. ;
  44.     extrn    sched_int: far
  45.     Globext    inc_counter
  46.     Globext    set_flag
  47. ;
  48.     extrn    tsk_key_avail: byte
  49.     extrn    tsk_glob_rec: byte
  50.     extrn    tsk_timer_counter:word
  51.     extrn    tsk_instflags: word
  52.     IF    NOT INT8_EARLY
  53.     extrn    tsk_int8_counter:word
  54.     ENDIF
  55. ;
  56.     IF    DEBUG AND DEB_FLASHERS
  57.     Locext    tsk_inccdis
  58.     extrn    tsk_debflash: word
  59.     extrn    tsk_dtposn: dword
  60.     ENDIF
  61. ;
  62. ;
  63. STACKSIZE    =    128    ; local stack size (words)
  64. ;
  65. timer    equ    40h            ; 8253 timer base I/O address
  66. inta00    equ    20h            ; 8259 int controller base
  67. eoi    equ    20h            ; unspecific EOI
  68. ;
  69. intseg    segment at 0
  70. ;
  71.         org    8*4
  72. tintofs        dw    ?        ; timer interrupt entry
  73. tintseg        dw    ?
  74.  
  75. intseg    ends
  76. ;
  77. biosdataseg    segment at 40h
  78.     org    1ah
  79. kbdptr1    dw    ?
  80. kbdptr2    dw    ?
  81. biosdataseg    ends
  82. ;
  83.     IF    FAR_STACKS
  84. ctask_stacks    segment word public 'CTASK_STACKS'
  85.     ELSE
  86.     .tsk_data
  87.     ENDIF
  88. ;
  89.     dw    STACKSIZE dup(?)
  90. local_stack    label    word
  91. ;
  92.     IF    FAR_STACKS
  93. ctask_stacks    ends
  94.     .tsk_data
  95.     ENDIF
  96. ;
  97. divisor        dw    ?
  98. timflag        dw    ?
  99. timcnt        dw    ?
  100. sys_ticks    dw    ?
  101. ;
  102.     .tsk_edata
  103.     .tsk_code
  104. ;
  105. tsk_dgroup    dw    @CTASK_DATA
  106. ;
  107.     IF    FAR_STACKS
  108. stackseg    dw    SEG ctask_stacks
  109.     ELSE
  110. stackseg    equ    <tsk_dgroup>
  111.     ENDIF
  112. ;
  113. timer_save    label    dword        ; in CSEG to allow addressing
  114. tsofs        dw    ?
  115. tsseg        dw    ?
  116. ;
  117. r_ss        dw    ?
  118. r_sp        dw    ?
  119. in_timer    db    0
  120. ;
  121. ;----------------------------------------------------------------------
  122. ;
  123.      IF    NOT INT8_EARLY
  124. ;
  125. ;    Timer interrupt handler, late INT 8 processing
  126. ;
  127. ;    Normal timer tick. The tick counter is incremented, and
  128. ;    the interrupt controller is checked for other pending interrupts.
  129. ;    If the timer tick occurred during processing of another interrupt,
  130. ;    we may not call the scheduler, since this would delay the
  131. ;    interrupt handler.
  132. ;
  133. ;    Note that an EOI is issued here to allow interrupts to occur
  134. ;    during further processing. The original INT 8 handler will be
  135. ;    chained to from a special task. The reason behind this is that
  136. ;    some TSR's link into the timer interrupt and may do some lengthy
  137. ;    processing there. To allow the TSR to be preempted, we must use
  138. ;    a task for the INT 8 processing.
  139. ;
  140. @timer_int_late    proc    far
  141. ;
  142. ;    first, check for overrun. If we're already processing a tick,
  143. ;    we simply ignore this one. That's not that great a way to
  144. ;    react, but anything else would easily mess things up, and we're
  145. ;    already in trouble anyway if this should happen.
  146. ;
  147.     cmp    cs:in_timer,0
  148.     je    timer_ok
  149.     push    ax
  150.     mov    al,eoi            ; issue EOI
  151.     out    inta00,al
  152.     pop    ax
  153.     iret
  154. ;
  155. ;    Not a second interrupt, continue processing. First, set the
  156. ;    in_timer marker, and switch to our local stack.
  157. ;
  158. timer_ok:
  159.     inc    cs:in_timer
  160.     mov    cs:r_ss,ss
  161.     mov    cs:r_sp,sp
  162.     mov    ss,cs:stackseg
  163.     mov    sp,offset local_stack
  164.     sti
  165.     cld
  166.     push    ax
  167.     push    ds
  168.     mov    ds,cs:tsk_dgroup
  169. ;
  170.     IF    DEBUG AND DEB_FLASHERS
  171.     cmp    tsk_debflash,0
  172.     je    debdd0
  173.     mov    ax,DEBP_CNTTICK
  174.     call    tsk_inccdis
  175. debdd0:
  176.     ENDIF
  177. ;
  178.     push    es            ; save other regs
  179.     push    bx
  180.     push    cx
  181.     push    dx
  182.     push    si
  183.     push    di
  184.     push    bp
  185.     callp    inc_counter,<<ds,#tsk_timer_counter>> ; increase timer tick counter
  186. ;
  187. ;    Now the timer counter is decremented. If it is zero,
  188. ;    we must chain to the original INT 8, so the counter for
  189. ;    the chain task is incremented.
  190. ;
  191.     dec    timcnt            ; decrement tick count
  192.     jnz    no_pass            ; pass on this int if zero
  193. ;
  194.     mov    ax,sys_ticks
  195.     mov    timcnt,ax        ; re-init tick counter
  196. ;
  197.     callp    inc_counter,<<ds,#tsk_int8_counter>>
  198. ;
  199. ;    Now we decrement all installed tick counters 
  200. ;
  201. no_pass:
  202.     les    bx,tsk_glob_rec.ticker_chain
  203. ;
  204. count_dec:
  205.     mov    ax,es
  206.     or    ax,bx
  207.     jz    tick_ready
  208.     mov    ax,es:ticklo[bx]
  209.     or    ax,es:tickhi[bx]
  210.     jz    count_next
  211.     sub    es:ticklo[bx],1
  212.     sbb    es:tickhi[bx],0
  213. count_next:
  214.     les    bx,es:ticknext[bx]
  215.     jmp    count_dec
  216. ;
  217. ;    Now check the BIOS keyboard buffer.
  218. ;    If there are chars in the buffer, set the tsk_key_avail flag
  219. ;    to wake up tasks waiting for the keyboard. This check is required
  220. ;    to find out about keyboard stuffers placing characters directly
  221. ;    into the keyboard buffer.
  222. ;
  223. tick_ready:
  224.     mov    ax,SEG biosdataseg
  225.     mov    es,ax
  226.     assume    es:biosdataseg
  227.     mov    ax,es:kbdptr1
  228.     cmp    ax,es:kbdptr2
  229.     assume    es:@CTASK_DATA
  230.     je    tick_exit
  231.     callp    set_flag,<<ds,#tsk_key_avail>>
  232. ;
  233. tick_exit:
  234.     pop    bp
  235.     pop    di
  236.     pop    si
  237.     pop    dx
  238.     pop    cx
  239.     pop    bx
  240.     pop    es
  241. ;
  242.     cli
  243.     mov    al,eoi            ; issue EOI
  244.     out    inta00,al
  245.     mov    al,0bh            ; access int control reg
  246.     out    inta00,al
  247.     in    al,inta00        ; ints pending?
  248.     or    al,al
  249.     jnz    tim_retn        ; don't schedule if other ints active
  250.     IF    DEBUG AND DEB_FLASHERS
  251.     cmp    tsk_debflash,0
  252.     je    debdda1
  253.     push    bx
  254.     lds    bx,tsk_dtposn
  255.     mov    byte ptr [bx+DEBP_CNTTICK+DEBFLASH_NDIGS*2],'+'
  256.     pop    bx
  257. debdda1:
  258.     ENDIF
  259.     pop    ds
  260.     pop    ax
  261.     mov    ss,cs:r_ss
  262.     mov    sp,cs:r_sp
  263.     dec    cs:in_timer
  264.     jmp    sched_int        ; else schedule
  265. ;
  266. tim_retn:
  267.     IF    DEBUG AND DEB_FLASHERS
  268.     cmp    tsk_debflash,0
  269.     je    debdda2
  270.     push    bx
  271.     lds    bx,tsk_dtposn
  272.     mov    byte ptr [bx+DEBP_CNTTICK+DEBFLASH_NDIGS*2],'-'
  273.     pop    bx
  274. debdda2:
  275.     ENDIF
  276.     pop    ds
  277.     pop    ax
  278.     mov    ss,cs:r_ss
  279.     mov    sp,cs:r_sp
  280.     dec    cs:in_timer
  281.     iret
  282. ;
  283. @timer_int_late    endp
  284. ;
  285.     ENDIF
  286. ;
  287. ;----------------------------------------------------------------------
  288. ;
  289.      IF    NOT INT8_LATE
  290. ;
  291. ;    Timer interrupt handler, early INT 8 processing
  292. ;
  293. ;    With this interrupt handler, the original INT 8 is chained to
  294. ;    directly, before calling the scheduler.
  295. ;
  296. ;    This avoids compatibility problems with TSR's that do strange
  297. ;    things in the timer tick, but it may lead to problems within
  298. ;    CTask, should the strange TSR decide to loop in the INT 8 handler,
  299. ;    or even to never return. Oh well, you can't please all TSR's all
  300. ;    of the time...
  301. ;
  302. @timer_int_early    proc    far
  303. ;
  304.     cld
  305.     push    ax
  306.     push    ds
  307.     mov    ds,cs:tsk_dgroup
  308. ;
  309.     IF    DEBUG AND DEB_FLASHERS
  310.     cmp    tsk_debflash,0
  311.     je    debdd1
  312.     mov    ax,DEBP_CNTTICK
  313.     call    tsk_inccdis
  314. debdd1:
  315.     ENDIF
  316. ;
  317. ;    The timer counter is decremented. If it is zero,
  318. ;    we chain directly to the original INT 8.
  319. ;    Since the local stack is not yet in use, 
  320. ;    multiple entries into this part are possible.
  321. ;
  322.     xor    ah,ah            ; no delayed tick
  323.     dec    timcnt            ; decrement tick count
  324.     jnz    eno_pass
  325. ;
  326.     mov    ax,sys_ticks
  327.     mov    timcnt,ax        ; re-init tick counter
  328. ;
  329. ;    Version 2.1 adds a check for scheduler active here.
  330. ;    We may not call the original INT 8 if the scheduler is active,
  331. ;    since this would crash the system when the old INT 8 causes
  332. ;    a task_wait. See tskasm.asm for a more detailed explanation.
  333. ;
  334.     cmp    tsk_glob_rec.in_sched,0
  335.     je    call_oldint
  336. ;
  337.     mov    ah,1            ; mark delayed tick
  338.     jmp    short eno_pass
  339. ;
  340. call_oldint:
  341.     sti
  342.     pop    ds
  343.     pop    ax
  344.     pushf
  345.     call    cs:timer_save        ; call original INT 8
  346.     push    ax
  347.     push    ds
  348.     mov    ds,cs:tsk_dgroup
  349.     xor    ah,ah            ; no delayed tick
  350.     jmp    short e_pass
  351. ;
  352. ;    On return from INT 8 processing, or when INT 8 was not chained,
  353. ;    processing is pretty much the same as in timer_int_late.
  354. ;
  355. eno_pass:
  356.     mov    al,eoi            ; issue EOI when not chained
  357.     out    inta00,al
  358. ;
  359. e_pass:
  360.     cli
  361.     cmp    cs:in_timer,0
  362.     je    etimer_ok
  363.     pop    ds
  364.     pop    ax
  365.     iret
  366. ;
  367. etimer_ok:
  368.     inc    cs:in_timer
  369.     mov    cs:r_ss,ss
  370.     mov    cs:r_sp,sp
  371.     mov    ss,cs:stackseg
  372.     mov    sp,offset local_stack
  373.     sti
  374.     cld
  375. ;
  376.     push    es            ; save other regs
  377.     push    bx
  378.     push    cx
  379.     push    dx
  380.     push    si
  381.     push    di
  382.     push    bp
  383. ;
  384. ;    If the tick was delayed, we have to notify the tsk_int8 to
  385. ;    process an additional tick when there's time.
  386. ;
  387.     IF    NOT INT8_EARLY
  388.     or    ah,ah            ; check delay flag
  389.     jz    no_delay
  390.     callp    inc_counter,<<ds,#tsk_int8_counter>>
  391.     ENDIF
  392. ;
  393. no_delay:
  394.     callp    inc_counter,<<ds,#tsk_timer_counter>> ; increase timer tick counter
  395. ;
  396. ;    Now we decrement all installed tick counters 
  397. ;
  398.     les    bx,tsk_glob_rec.ticker_chain
  399. ;
  400. ecount_dec:
  401.     mov    ax,es
  402.     or    ax,bx
  403.     jz    etick_ready
  404.     mov    ax,es:ticklo[bx]
  405.     or    ax,es:tickhi[bx]
  406.     jz    ecount_next
  407.     sub    es:ticklo[bx],1
  408.     sbb    es:tickhi[bx],0
  409. ecount_next:
  410.     les    bx,es:ticknext[bx]
  411.     jmp    ecount_dec
  412. ;
  413. ;    Now check the BIOS keyboard buffer.
  414. ;    If there are chars in the buffer, set the tsk_key_avail flag
  415. ;    to wake up tasks waiting for the keyboard. This check is required
  416. ;    to find out about keyboard stuffers placing characters directly
  417. ;    into the keyboard buffer.
  418. ;
  419. etick_ready:
  420.     mov    ax,SEG biosdataseg
  421.     mov    es,ax
  422.     assume    es:biosdataseg
  423.     mov    ax,es:kbdptr1
  424.     cmp    ax,es:kbdptr2
  425.     assume    es:@CTASK_DATA
  426.     je    etick_exit
  427.     callp    set_flag,<<ds,#tsk_key_avail>>
  428. ;
  429. etick_exit:
  430.     pop    bp
  431.     pop    di
  432.     pop    si
  433.     pop    dx
  434.     pop    cx
  435.     pop    bx
  436.     pop    es
  437. ;
  438.     cli
  439.     mov    al,0bh            ; access int control reg
  440.     out    inta00,al
  441.     in    al,inta00        ; ints pending?
  442.     or    al,al
  443.     jnz    etim_retn        ; don't schedule if other ints active
  444.     mov    ss,cs:r_ss
  445.     mov    sp,cs:r_sp
  446.     pop    ds
  447.     pop    ax
  448.     dec    cs:in_timer
  449.     jmp    sched_int        ; else schedule
  450. ;
  451. etim_retn:
  452.     mov    tsk_glob_rec.pretick,1    ; mark that we missed a schedule
  453.     mov    ss,cs:r_ss
  454.     mov    sp,cs:r_sp
  455.     pop    ds
  456.     pop    ax
  457.     dec    cs:in_timer
  458.     iret
  459. ;
  460. @timer_int_early    endp
  461. ;
  462.     ENDIF
  463. ;
  464. ;---------------------------------------------------------------------
  465. ;
  466. ;    Install timer.
  467. ;    The scheduler is not called on this first tick.
  468. ;
  469. @tim_install    proc    far
  470. ;
  471.     push    ax
  472.     push    ds
  473.     push    es
  474. ;
  475.     mov    ds,cs:tsk_dgroup
  476. ;
  477.     mov    timflag,0        ; signal init ready
  478.     mov    ax,sys_ticks
  479.     mov    timcnt,ax        ; init tick counter
  480.     mov    al,36h
  481.     out    timer+3,al        ; setup to load divisor
  482.     mov    al,byte ptr divisor
  483.     out    timer,al        ; lsb
  484.     mov    al,byte ptr divisor+1
  485.     out    timer,al        ; msb
  486. ;
  487.     xor    ax,ax
  488.     mov    es,ax
  489.     assume    es:intseg
  490. ;
  491.     IF    INT8_EARLY
  492.     mov    ax,offset @timer_int_early
  493.     ELSE
  494.     mov    ax,offset @timer_int_late
  495.     IF    NOT INT8_LATE
  496.     test    tsk_instflags,IFL_INT8_DIR
  497.     jz    tim_inst_1
  498.     mov    ax,offset @timer_int_early
  499.     ENDIF
  500.     ENDIF
  501. ;
  502. tim_inst_1:
  503.     mov    es:tintofs,ax
  504.     mov    es:tintseg,cs
  505. ;
  506.     pop    es
  507.     pop    ds
  508.     pop    ax
  509.     jmp    cs:timer_save
  510. ;
  511. @tim_install    endp
  512. ;
  513. ;------------------------------------------------------------------------
  514. ;
  515. ;       Un-Install timer (wait until system tick count reached).
  516. ;    The scheduler is not called while waiting for the tick count.
  517. ;
  518. @tim_uninstall    proc    far
  519. ;
  520.     push    ax
  521.     push    ds
  522. ;
  523.     mov    ds,cs:tsk_dgroup
  524. ;
  525.     cli
  526.     dec    timcnt            ; decrement tick count
  527.     jz    uninit            ; go un-install if zero
  528.     mov    al,eoi            ; else just issue EOI
  529.     out    inta00,al
  530.     pop    ds
  531.     pop    ax
  532.     iret
  533. ;
  534. ;    Uninstall timer int handler
  535. ;
  536. uninit:
  537.     mov    timflag,0        ; mark un-install complete
  538.     mov    al,36h            ; setup to load divisor
  539.     out    timer+3,al
  540.     mov    al,0            ; divisor 0 means 65536
  541.     out    timer,al        ; lsb
  542.     out    timer,al        ; msb
  543. ;
  544.     push    es
  545.     xor    ax,ax
  546.     mov    es,ax
  547.     assume    es:intseg
  548.     mov    ax,cs:tsofs        ; restore vector
  549.     mov    tintofs,ax
  550.     mov    ax,cs:tsseg
  551.     mov    tintseg,ax
  552.     pop    es
  553.     pop    ds
  554.     pop    ax
  555.     jmp    cs:timer_save        ; pass on interrupt
  556. ;
  557. @tim_uninstall    endp
  558. ;
  559. ;----------------------------------------------------------------------
  560. ;
  561.     IF    NOT INT8_EARLY
  562. ;
  563. ;    void far tsk_chain_timer (void)
  564. ;
  565. ;       Pass timer tick on to interrupt 8 chain.
  566. ;
  567. Localfunc tsk_chain_timer
  568. ;
  569.     IF    DEBUG AND DEB_FLASHERS
  570.     cmp    tsk_debflash,0
  571.     je    debdd2
  572.     mov    ax,DEBP_CNTTCHAIN
  573.     call    tsk_inccdis
  574. debdd2:
  575.     ENDIF
  576.     pushf
  577.     cli
  578.     call    cs:timer_save
  579.     ret
  580. ;
  581. tsk_chain_timer    endp
  582. ;
  583.     ENDIF
  584. ;
  585. ;
  586. ;    void near tsk_install_timer (word divisor, word sys_ticks)
  587. ;
  588. ;    This routine installs the timer tick int handler.
  589. ;    The timer chip is reprogrammed on the next tick.
  590. ;
  591. Localfunc tsk_install_timer,<pdivisor: word, psysticks: word>
  592. ;
  593.     IFDEF    LOAD_DS
  594.     push    ds
  595.     mov    ds,cs:tsk_dgroup
  596.     ENDIF
  597. ;
  598.     mov    ax,pdivisor
  599.     mov    divisor,ax
  600.     mov    ax,psysticks
  601.     mov    sys_ticks,ax
  602.     mov    timflag,1        ; set init-flag
  603.     xor    ax,ax
  604.     mov    es,ax            ; establish addressing for intseg
  605.     assume    es:intseg
  606. ;
  607.     mov    ax,tintofs        ; save old timer int addr
  608.     mov    tsofs,ax
  609.     mov    ax,tintseg
  610.     mov    tsseg,ax
  611.     cli
  612.     mov    tintofs,offset @tim_install ; set new timer int addr
  613.     mov    tintseg,cs
  614.     sti
  615.     assume    es:nothing
  616. wait_set:
  617.     cmp    timflag,0        ; wait until timer started
  618.     jne    wait_set
  619.     IFDEF    LOAD_DS
  620.     pop    ds
  621.     ENDIF
  622.     ret
  623. ;
  624. tsk_install_timer    endp
  625. ;
  626. ;
  627. ;    void far tsk_remove_timer (void)
  628. ;
  629. ;    This routine un-installs the timer tick int handler.
  630. ;    The timer chip is reprogrammed & the interrupt vector
  631. ;    restored when the system tick count reaches zero.
  632. ;
  633. Localfunc tsk_remove_timer
  634. ;
  635.     IFDEF    LOAD_DS
  636.     push    ds
  637.     mov    ds,cs:tsk_dgroup
  638.     ENDIF
  639. ;
  640.     mov    timflag,2        ; set un-init flag for timer
  641.  
  642.     xor    ax,ax
  643.     mov    es,ax            ; establish addressing for intseg
  644.     assume    es:intseg
  645. ;
  646.     cli
  647.     mov    tintofs,offset @tim_uninstall ; set new timer int addr
  648.     mov    tintseg,cs
  649.     sti
  650.     assume    es:nothing
  651. wait_tim:
  652.         sti                             ; just to be safe
  653.     cmp    timflag,0        ; wait until int un-installed
  654.     jne    wait_tim
  655.     IFDEF    LOAD_DS
  656.     pop    ds
  657.     ENDIF
  658.     ret
  659. ;
  660. tsk_remove_timer    endp
  661. ;
  662.     .tsk_ecode
  663.     end
  664.  
  665.