📄 tskasm.asm
字号:
mov cx,l_swap[bx] ; swap area addr & size
jcxz no_swap_sav
lds si,dos_vars[bx]
rep movsb
;
no_swap_sav:
xor cx,cx ; copy int21-24 interrupt vectors
mov ds,cx
mov si,21h*4
mov cx,8
rep movsw
;
pop di
pop ds
ENDIF
;
; if EMS support is installed, call the page map save function.
;
IF EMS
mov ax,word ptr ems_save[bx]
or ax,word ptr ems_save+2[bx]
jz no_emssav
call ems_save[bx]
;
no_emssav:
ENDIF
;
; If the NDP is active, save the NDP context.
;
IF NDP
test es:flags[di],F_USES_NDP
jz no_ndpsave
wait
fsave es:ndpsave[di]
;
no_ndpsave:
ENDIF
;
; Save complete. The new TCB becomes the current task.
;
set_new_task:
IF DEBUG AND DEB_TSKDIS
push ds
mov ds,cs:tsk_dgroup
cmp tsk_debtask,0
je deb205
les di,tsk_dtposn
pop ax ; saved DS
pop ds ; the new task's TCB
pop si
push si
push ds
push ax ; saved DS
mov byte ptr es:[di],'+'
add di,DEBP_CURRTSK
lea si,tname.nname[si]
call @strcpy8
pop ds
push ds
lds si,current_task[bx] ; the previous task
lea si,tname.nname[si]
call @strcpy8
pop ds
push ds
lds si,eligible_queue.q_first[bx]
test q_kind[si],Q_HEAD
jnz deb201
push si
lea si,tname.nname[si]
call @strcpy8
pop si
lds si,q_next[si]
test q_kind[si],Q_HEAD
jnz deb202
lea si,tname.nname[si]
call @strcpy8
jmp short deb205
;
deb201:
fill8
deb202:
fill8
deb205:
pop ds
ENDIF
pop es
pop di
cli
mov word ptr current_task[bx],di ; set tcb into current
mov word ptr current_task+2[bx],es
sti
;
; if EMS support is installed, call the page map restore function.
;
IF EMS
mov ax,word ptr ems_rest[bx]
or ax,word ptr ems_rest+2[bx]
jz no_emsrest
call ems_rest[bx]
no_emsrest:
ENDIF
;
; Now check for a restore function in the new TCB.
;
mov ax,word ptr es:rest_func[di]
or ax,word ptr es:rest_func+2[di]
jz no_resfcall ; jump if no restore function
;
push bx ; save our regs
push ds
push di
push es
;
push es ; push TCB addr
push es ; push segment again
pop ds ; and put into DS
push di
;
call es:rest_func[di] ; call restore function
add sp,4
;
pop es
pop di
pop ds
pop bx
;
no_resfcall:
;
; If NDP is enabled, restore 80x87 context.
;
IF NDP
test es:flags[di],F_USES_NDP
jz no_ndprest
cmp es:t_new[di],0 ; is this TCB a fresh one?
jne no_ndprest ; then NDP state isn't valid
;
wait
frstor es:ndpsave[di]
;
no_ndprest:
ENDIF
;
; Restore DOS variables and int vectors from new TCB.
;
IF DOS
;; cmp es:t_new[di],0 ; is this TCB a fresh one?
;; jne sched_complete ; then the DOS info isn't valid.
;
push di
push es
push ds
mov dx,ds
mov ax,es
mov ds,ax
mov si,di
add si,base_psp
lodsw
mov es,ax
mov di,psp_savoff ; offset to restore (caller's SS:SP)
cli
movsw ; restore two words
movsw
sti
;
mov ax,ds
mov ds,dx
mov cx,l_swap[bx]
jcxz no_swap_rest
les di,dos_vars[bx]
mov ds,ax
rep movsb
;
no_swap_rest:
mov ds,ax
mov di,21h*4 ; restore int21-24
xor cx,cx
mov es,cx
mov cx,8
cli
rep movsw
sti
;
pop ds
pop es
pop di
ENDIF
;
; And that's it. Wrap it up by resetting the priority,
; restoring the registers, resetting the in_sched flag,
; and returning to the task.
; Note: to allow keeping interrupts enabled as long as possible,
; the in_sched flag is cleared after reloading the registers.
;
sched_complete:
mov ax,es:q_el.q_ini_prior[di] ; reset current tasks priority
mov es:q_el.q_prior[di],ax
mov es:state[di],ST_RUNNING ; set task state
;
push es
push di
IF DEBUG AND DEB_TSKDIS
mov ds,cs:tsk_dgroup
cmp tsk_debtask,0
je debddx
les di,tsk_dtposn
mov byte ptr es:[di],' '
debddx:
ENDIF
pop bx
pop ds
mov es,t_es[bx] ; restore all registers
mov di,t_di[bx]
mov si,t_si[bx]
mov bp,t_bp[bx]
mov dx,t_dx[bx]
mov cx,t_cx[bx]
mov ax,t_ax[bx]
mov ss,t_ss[bx]
mov sp,t_sp[bx]
;
; All done except for resetting the in_sched flag.
; Now we check the preemption tick flag, and restart the schedule
; if it is set. To avoid needless reschedules, the priority of the
; current task is compared to the priority of the first task in
; the eligible queue. If there is no task eligible, or if its
; priority is less or equal to the current task, the current task
; is allowed to continue.
;
mov ds,cs:tsk_dgroup
cli
IF SINGLE_DATA
cmp tsk_glob_rec.pretick,0
je sched_end
mov bx,offset tsk_glob_rec
ELSE
lds bx,tsk_global
cmp pretick[bx],0
je sched_end
ENDIF
;
push es
push di
les di,current_task[bx] ; get current tcb again
lds bx,eligible_queue.q_first[bx]
test q_kind[bx],Q_HEAD
jnz no_restart
mov bx,cqueue.q_el.q_prior[bx] ; prior of eligible task
cmp bx,es:cqueue.q_el.q_prior[di] ; prior of current task
jbe no_restart
;
; Note: registers don't have to be popped, since the stack
; is reset anyway at the sched_restart entry.
;
do_rest:
jmp sched_restart
;
;
no_restart:
pop di
pop es
mov ds,cs:tsk_dgroup
IF NOT SINGLE_DATA
lds bx,tsk_global
ENDIF
;
sched_end:
IF SINGLE_DATA
mov tsk_glob_rec.in_sched,0
IF DOS
lds bx,tsk_glob_rec.dos_in_use
dec byte ptr [bx]
ENDIF
ELSE
mov in_sched[bx],0
IF DOS
lds bx,dos_in_use[bx]
dec byte ptr [bx]
ENDIF
ENDIF
;
pop bx
pop ds
iret
;
tsk_scheduler endp
;
;
;--------------------------------------------------------------------------
;
;
; sched_int
;
; Is the scheduler entry for interrupt handlers.
; It checks if preemption is allowed, returning if not.
; The stack is assumed to be set up as on interrupt entry.
;
sched_int proc far
;
push ds
push bx
mov ds,cs:tsk_dgroup
IF SINGLE_DATA
mov bx,offset tsk_glob_rec
ELSE
lds bx,tsk_global
ENDIF
cmp preempt[bx],0 ; preempt flags 0?
jne no_sched1 ; no scheduling if set
lds bx,current_task[bx] ; current running task
test flags[bx],F_CRIT ; preemption allowed for this task?
jnz no_sched ; no scheduling if flag set
pop bx ; else go schedule
pop ds
jmp tsk_scheduler
;
no_sched:
mov ds,cs:tsk_dgroup
IF SINGLE_DATA
mov bx,offset tsk_glob_rec
ELSE
lds bx,tsk_global
ENDIF
no_sched1:
mov pretick[bx],1 ; Mark preemption pending
pop bx
pop ds
iret
;
sched_int endp
;
;
; void far schedule (void)
;
; Entry for calling the scheduler. Rearranges the stack to
; contain flags.
; NOTE: Uses ax,bx.
;
Globalfunc schedule
;
IF NEAR_CODE
pop ax
pushf
push cs
push ax
ELSE
pop ax
pop bx
pushf
push bx
push ax
ENDIF
cli
jmp tsk_scheduler
;
schedule endp
;
;
; void far yield (void)
;
; Entry for calling the scheduler with priority temporarily
; set to zero. Rearranges the stack to contain flags.
; NOTE: Uses ax,bx, es.
;
Globalfunc yield
;
IF NEAR_CODE
pop ax
pushf
push cs
push ax
ELSE
pop ax
pop bx
pushf
push bx
push ax
ENDIF
;
IF SINGLE_DATA
IFDEF LOAD_DS
mov es,cs:tsk_dgroup
les bx,es:tsk_glob_rec.current_task
ELSE
les bx,tsk_glob_rec.current_task
ENDIF
ELSE
IFDEF LOAD_DS
mov es,cs:tsk_dgroup
les bx,es:tsk_global
ELSE
les bx,tsk_global
ENDIF
les bx,es:current_task[bx]
ENDIF
cli
mov es:q_el.q_prior[bx],0
jmp tsk_scheduler
;
yield endp
;
;
; void far c_schedule (void)
;
; Entry for conditionally calling the scheduler. Rearranges
; the stack to contain flags, then jumps to _sched_int.
; NOTE: Uses ax,bx.
;
Globalfunc c_schedule
;
IF NEAR_CODE
pop ax
pushf
push cs
push ax
ELSE
pop ax
pop bx
pushf
push bx
push ax
ENDIF
cli
jmp sched_int
;
c_schedule endp
;
;--------------------------------------------------------------------------
;
; void tsk_callfunc (farptr funcad, farptr param)
;
; Calls the given function, placing the segment address of
; the parameter into the DS register.
;
Globalfunc tsk_callfunc,<uses ds, funcad: far ptr, param: far ptr>
;
lds ax,param
push ds
push ax
call funcad
add sp,4
ret
tsk_callfunc endp
;
;
; word tsk_dseg (void)
;
; Returns current contents of DS register.
;
Globalfunc tsk_dseg
mov ax,ds
ret
tsk_dseg endp
;
;
; word tsk_flags (void)
;
; Returns current contents of Flag register.
;
Globalfunc tsk_flags
pushf
pop ax
ret
tsk_flags endp
;
;
; int tsk_dis_int (void)
;
; Returns current state of the interrupt flag (1 if ints were
; enabled), then disables interrupts.
;
Globalfunc tsk_dis_int
;
pushf
pop ax
mov al,ah
shr al,1
and ax,1
cli
ret
;
tsk_dis_int endp
;
;
; void far tsk_ena_int (int state)
;
; Enables interrupts if 'state' is nonzero.
;
Globalfunc tsk_ena_int,<istate: word>
;
cmp istate,0
je teiend
sti
teiend:
ret
;
tsk_ena_int endp
;
;
; tsk_cli/tsk_sti: disable/enable int
; NOTE: These routines are normally replaced by intrinsics.
;
Globalfunc tsk_cli
cli
ret
tsk_cli endp
;
;
Globalfunc tsk_sti
sti
ret
tsk_sti endp
;
;
; tsk_inp/tsk_outp: input/output from/to port
; NOTE: These routines are normally replaced by intrinsics,
; except for Turbo C tsk_inpw.
;
Globalfunc tsk_inp,<port: word>
;
mov dx,port
in al,dx
xor ah,ah
ret
;
tsk_inp endp
;
;
Globalfunc tsk_inpw,<port: word>
;
mov dx,port
in ax,dx
ret
;
tsk_inpw endp
;
;
Globalfunc tsk_outp,<port: word, val: word>
;
mov dx,port
mov al,byte ptr(val)
out dx,al
ret
;
tsk_outp endp
;
;
; void tsk_nop (void)
;
; Do nothing. Used for very short delays.
;
Globalfunc tsk_nop
;
jmp short tnop1
tnop1:
jmp short tnop2
tnop2:
ret
;
tsk_nop endp
;
;
; void tsk_memcpy (farptr dest, farptr src, word nbytes)
;
Globalfunc tsk_memcpy,<uses ds si di, dest: far ptr, src: far ptr, len: word>
;
mov cx,len
lds si,src
les di,dest
xor bx,bx
shr cx,1
rcl bx,1
jcxz cpy_byte
rep movsw
cpy_byte:
or bx,bx
jz cpy_end
movsb
cpy_end:
ret
;
tsk_memcpy endp
;
;
IF CLOCK_MSEC
;
; dword Localfunc tsk_timeout (dword tout)
;
; Translates milliseconds to clock ticks using integer arithmetic.
; Routine provided by Chris Blum.
;
Localfunc tsk_timeout,<tout:dword>
;
mov dh,byte ptr tout
mov dl,byte ptr tout+3
mov ax,word ptr tout+1
or dx,dx
jnz tsk_timmax
or ax,ax
jz tsk_timok
tsk_timmax:
push ds
mov ds,cs:tsk_dgroup
IF SINGLE_DATA
mov bx,offset tsk_glob_rec
ELSE
lds bx,tsk_global
ENDIF
mov cx,tick_factor[bx]
pop ds
xor dh,dh
cmp cx,dx
jbe tsk_timhi
div cx
mov bx,ax
xor al,al
mov ah,byte ptr tout
div cx
inc cx
shr cx,1
cmp dx,cx
mov dx,bx
jb tsk_timmin
add ax,1
adc dx,0
jnc tsk_timok
tsk_timhi:
mov ax,0ffffh
mov dx,ax
jmp short tsk_timok
tsk_timmin:
or ax,ax
jnz tsk_timok
or dx,dx
jnz tsk_timok
inc ax
tsk_timok:
ret
;
tsk_timeout endp
;
ENDIF
;
IF DOS
;
Localfunc tsk_get_dosswap,<uses ds si di, tcbp:far ptr>
;
IFDEF LOAD_DS
mov ds,cs:tsk_dgroup
ENDIF
IF SINGLE_DATA
mov bx,offset tsk_glob_rec
ELSE
lds bx,tsk_global
ENDIF
les di,tcbp
mov ax,ds
mov ds,es:base_psp[di] ; get base PSP address
mov si,psp_savoff ; offset to save (caller's SS:SP)
add di,psp_sssp ; destination
movsw ; save two words
movsw
mov ds,ax
mov cx,l_swap[bx] ; swap area addr & size
jcxz gd_no_swap
lds si,dos_vars[bx]
rep movsb
;
gd_no_swap:
xor cx,cx ; copy int21-24 interrupt vectors
mov ds,cx
mov si,21h*4
mov cx,8
rep movsw
;
ret
;
tsk_get_dosswap endp
;
ENDIF
;
.tsk_ecode
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -