⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tskasm.asm

📁 一个多任务操作系统CTask的源代码 用C语言编写
💻 ASM
📖 第 1 页 / 共 2 页
字号:
	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 + -