home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frostbyte's 1980s DOS Shareware Collection
/
floppyshareware.zip
/
floppyshareware
/
DOOG
/
CTASK.ZIP
/
TSKTIM.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-12-20
|
10KB
|
498 lines
;
; --- Version 2.0 89-12-13 17:34 ---
;
; CTask - Timer interrupt handler (IBM specific)
;
; Public Domain Software written by
; Thomas Wagner
; Patschkauer Weg 31
; D-1000 Berlin 33
; West Germany
;
; NOTE: Logic in this module has been changed to accommodate two
; different ways to handle chaining to the original INT 8
; entry in version 1.2.
;
name tsktim
.model large,c
;
public tsk_install_timer
public tsk_remove_timer
public tsk_chain_timer
;
include tsk.mac
;
extrn tsk_dgroup: word
extrn sched_int: far
extrn inc_counter: far
;
STACKSIZE = 128 ; local stack size (words)
;
timer equ 40h ; 8253 timer base I/O address
inta00 equ 20h ; 8259 int controller base
eoi equ 20h ; unspecific EOI
;
intseg segment at 0
;
org 8*4
tintofs dw ? ; timer interrupt entry
tintseg dw ?
intseg ends
;
;
.tsk_data
;
extrn tsk_glob_rec: byte
extrn tsk_timer_counter:word
extrn tsk_int8_counter:word
extrn tsk_instflags: word
;
divisor dw ?
timflag dw ?
timcnt dw ?
sys_ticks dw ?
;
dw STACKSIZE dup(?)
local_stack label word
;
.tsk_edata
.tsk_code
;
timer_save label dword ; in CSEG to allow addressing
tsofs dw ?
tsseg dw ?
;
r_ss dw ?
r_sp dw ?
in_timer db 0
;
;----------------------------------------------------------------------
;
; Timer interrupt handler, late INT 8 processing
;
; Normal timer tick. The tick counter is incremented, and
; the interrupt controller is checked for other pending interrupts.
; If the timer tick occurred during processing of another interrupt,
; we may not call the scheduler, since this would delay the
; interrupt handler.
;
; Note that an EOI is issued here to allow interrupts to occur
; during further processing. The original INT 8 handler will be
; chained to from a special task. The reason behind this is that
; some TSR's link into the timer interrupt and may do some lengthy
; processing there. To allow the TSR to be preempted, we must use
; a task for the INT 8 processing.
;
timer_int_late proc far
;
; first, check for overrun. If we're already processing a tick,
; we simply ignore this one. That's not that great a way to
; react, but anything else would easily mess things up, and we're
; already in trouble anyway if this should happen.
;
cmp cs:in_timer,0
je timer_ok
push ax
mov al,eoi ; issue EOI
out inta00,al
pop ax
iret
;
; Not a second interrupt, continue processing. First, set the
; in_timer marker, and switch to our local stack.
;
timer_ok:
inc cs:in_timer
mov cs:r_ss,ss
mov cs:r_sp,sp
mov ss,cs:tsk_dgroup
mov sp,offset local_stack
sti
cld
push ax
push ds
mov ds,cs:tsk_dgroup
;
norm_tick:
;
push es ; save other regs
push bx
push cx
push dx
push si
push di
push bp
mov ax,ds
mov es,ax
mov ax,offset tsk_timer_counter
push ds
push ax
call inc_counter ; increase timer tick counter
add sp,4
;
; Now the timer counter is decremented. If it is zero,
; we must chain to the original INT 8, so the counter for
; the chain task is incremented.
;
dec timcnt ; decrement tick count
jnz no_pass ; pass on this int if zero
;
mov ax,sys_ticks
mov timcnt,ax ; re-init tick counter
;
mov ax,offset tsk_int8_counter
push ds
push ax
call inc_counter ; increase timer tick counter
add sp,4
;
; Now we decrement all installed tick counters
;
no_pass:
les bx,tsk_glob_rec.ticker_chain
;
count_dec:
mov ax,es
or ax,bx
jz tick_ready
mov ax,es:ticklo[bx]
or ax,es:tickhi[bx]
jz count_next
sub es:ticklo[bx],1
sbb es:tickhi[bx],0
count_next:
les bx,es:ticknext[bx]
jmp count_dec
;
tick_ready:
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop es
;
cli
mov al,eoi ; issue EOI
out inta00,al
mov al,0bh ; access int control reg
out inta00,al
in al,inta00 ; ints pending?
or al,al
jnz tim_retn ; don't schedule if other ints active
pop ds
pop ax
mov ss,cs:r_ss
mov sp,cs:r_sp
dec cs:in_timer
jmp sched_int ; else schedule
;
tim_retn:
pop ds
pop ax
mov ss,cs:r_ss
mov sp,cs:r_sp
dec cs:in_timer
iret
;
timer_int_late endp
;
;----------------------------------------------------------------------
;
; Timer interrupt handler, early INT 8 processing
;
; With this interrupt handler, the original INT 8 is chained to
; directly, before calling the scheduler.
;
; This avoids compatibility problems with TSR's that do strange
; things in the timer tick, but it may lead to problems within
; CTask, should the strange TSR decide to loop in the INT 8 handler,
; or even to never return. Oh well, you can't please all TSR's all
; of the time...
;
timer_int_early proc far
;
cld
push ax
push ds
mov ds,cs:tsk_dgroup
;
; The timer counter is decremented. If it is zero,
; we chain directly to the original INT 8.
; Since the local stack is not yet in use,
; multiple entries into this part are possible.
;
dec timcnt ; decrement tick count
jnz eno_pass
;
mov ax,sys_ticks
mov timcnt,ax ; re-init tick counter
;
pop ds
pop ax
pushf
call cs:timer_save ; call original INT 8
cli
push ax
push ds
mov ds,cs:tsk_dgroup
jmp short e_pass
;
; On return from INT 8 processing, or when INT 8 was not chained,
; processing is pretty much the same as in timer_int_late.
;
eno_pass:
mov al,eoi ; issue EOI when not chained
out inta00,al
;
e_pass:
cmp cs:in_timer,0
je etimer_ok
pop ds
pop ax
iret
;
etimer_ok:
inc cs:in_timer
mov cs:r_ss,ss
mov cs:r_sp,sp
mov ss,cs:tsk_dgroup
mov sp,offset local_stack
sti
cld
;
push es ; save other regs
push bx
push cx
push dx
push si
push di
push bp
mov ax,ds
mov es,ax
mov ax,offset tsk_timer_counter
push ds
push ax
call inc_counter ; increase timer tick counter
add sp,4
;
; Now we decrement all installed tick counters
;
les bx,tsk_glob_rec.ticker_chain
;
ecount_dec:
mov ax,es
or ax,bx
jz etick_ready
mov ax,es:ticklo[bx]
or ax,es:tickhi[bx]
jz ecount_next
sub es:ticklo[bx],1
sbb es:tickhi[bx],0
ecount_next:
les bx,es:ticknext[bx]
jmp ecount_dec
;
etick_ready:
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop es
;
cli
mov al,0bh ; access int control reg
out inta00,al
in al,inta00 ; ints pending?
or al,al
jnz etim_retn ; don't schedule if other ints active
mov ss,cs:r_ss
mov sp,cs:r_sp
pop ds
pop ax
dec cs:in_timer
jmp sched_int ; else schedule
;
etim_retn:
mov ss,cs:r_ss
mov sp,cs:r_sp
pop ds
pop ax
dec cs:in_timer
iret
;
timer_int_early endp
;
;---------------------------------------------------------------------
;
; Install timer.
; The scheduler is not called on this first tick.
;
tim_install proc far
;
push ax
push ds
push es
;
mov ds,cs:tsk_dgroup
;
mov timflag,0 ; signal init ready
mov ax,sys_ticks
mov timcnt,ax ; init tick counter
mov al,36h
out timer+3,al ; setup to load divisor
mov al,byte ptr divisor
out timer,al ; lsb
mov al,byte ptr divisor+1
out timer,al ; msb
;
xor ax,ax
mov es,ax
assume es:intseg
mov ax,offset timer_int_late
test tsk_instflags,IFL_INT8_DIR
jz tim_inst_1
mov ax,offset timer_int_early
;
tim_inst_1:
mov es:tintofs,ax
mov es:tintseg,cs
;
pop es
pop ds
pop ax
jmp cs:timer_save
;
tim_install endp
;
;------------------------------------------------------------------------
;
; Un-Install timer (wait until system tick count reached).
; The scheduler is not called while waiting for the tick count.
;
tim_uninstall proc far
;
push ax
push ds
;
mov ds,cs:tsk_dgroup
;
cli
dec timcnt ; decrement tick count
jz uninit ; go un-install if zero
mov al,eoi ; else just issue EOI
out inta00,al
pop ds
pop ax
iret
;
; Uninstall timer int handler
;
uninit:
mov timflag,0 ; mark un-install complete
mov al,36h ; setup to load divisor
out timer+3,al
mov al,0 ; divisor 0 means 65536
out timer,al ; lsb
out timer,al ; msb
;
push es
xor ax,ax
mov es,ax
assume es:intseg
mov ax,cs:tsofs ; restore vector
mov tintofs,ax
mov ax,cs:tsseg
mov tintseg,ax
pop es
pop ds
pop ax
jmp cs:timer_save ; pass on interrupt
;
tim_uninstall endp
;
;----------------------------------------------------------------------
;
; void far tsk_chain_timer (void)
;
; Pass timer tick on to interrupt 8 chain.
;
tsk_chain_timer proc near
;
pushf
cli
call cs:timer_save
ret
;
tsk_chain_timer endp
;
;
; void near tsk_install_timer (word divisor, word sys_ticks)
;
; This routine installs the timer tick int handler.
; The timer chip is reprogrammed on the next tick.
;
tsk_install_timer proc near uses ds, pdivisor: word, psysticks: word
;
mov ds,cs:tsk_dgroup
mov ax,pdivisor
mov divisor,ax
mov ax,psysticks
mov sys_ticks,ax
mov timflag,1 ; set init-flag
xor ax,ax
mov es,ax ; establish addressing for intseg
assume es:intseg
;
mov ax,tintofs ; save old timer int addr
mov tsofs,ax
mov ax,tintseg
mov tsseg,ax
cli
mov tintofs,offset tim_install ; set new timer int addr
mov tintseg,cs
sti
assume es:nothing
wait_set:
cmp timflag,0 ; wait until timer started
jne wait_set
ret
;
tsk_install_timer endp
;
;
; void far tsk_remove_timer (void)
;
; This routine un-installs the timer tick int handler.
; The timer chip is reprogrammed & the interrupt vector
; restored when the system tick count reaches zero.
;
tsk_remove_timer proc near uses ds
;
mov ds,cs:tsk_dgroup
mov timflag,2 ; set un-init flag for timer
xor ax,ax
mov es,ax ; establish addressing for intseg
assume es:intseg
;
cli
mov tintofs,offset tim_uninstall ; set new timer int addr
mov tintseg,cs
sti
assume es:nothing
wait_tim:
sti ; just to be safe
cmp timflag,0 ; wait until int un-installed
jne wait_tim
ret
;
tsk_remove_timer endp
;
end