
		.386
		option	segment:use16

dseg		segment	para public 'data'

wp		equ	<word ptr>

; 32-bit PCB.  Note we only keep the L.O. 16 bits of SP since we are
; operating in real mode.

pcb32		struc
regsp		word	?
regss		word	?
regip		word	?
regcs		word	?

regeax		dword	?
regebx		dword	?
regecx		dword	?
regedx		dword	?
regesi		dword	?
regedi		dword	?
regebp		dword	?

regds		word	?
reges		word	?
regflags	dword	?
pcb32		ends


DefaultPCB	pcb32	<>
DefaultCortn	pcb32	<>

CurCoroutine	dd	DefaultCortn	;Points at the currently executing
					; coroutine.
dseg		ends


cseg		segment	para public 'slcode'

;============================================================================
;
; Coroutine support.
;
; COINIT- ES:DI contains the address of the current (default) process.

CoInit32	proc	far
		assume	ds:dseg
		push	ax
		push	ds
		mov	ax, dseg
		mov	ds, ax
		mov	wp dseg:CurCoroutine, di
		mov	wp dseg:CurCoroutine+2, es
		pop	ds
		pop	ax
		ret
CoInit32	endp


; COCALL32- transfers control to a coroutine.  ES:DI contains the address
; of the PCB.  This routine transfers control to that coroutine and then
; returns a pointer to the caller's PCB in ES:DI.

cocall32	proc	far
		assume	ds:dseg
		pushfd
		push	ds
		push	es			;Save these for later
		push	edi
		push	eax
		mov	ax, dseg
		mov	ds, ax
		cli				;Critical region ahead.


; Save the current process' state:

		les	di, dseg:CurCoroutine
		pop	es:[di].pcb32.regeax
		mov	es:[di].pcb32.regebx, ebx
		mov	es:[di].pcb32.regecx, ecx
		mov	es:[di].pcb32.regedx, edx
		mov	es:[di].pcb32.regesi, esi
		pop	es:[di].pcb32.regedi
		mov	es:[di].pcb32.regebp, ebp

		pop	es:[di].pcb32.reges
		pop	es:[di].pcb32.regds
		pop	es:[di].pcb32.regflags
		pop	es:[di].pcb32.regip
		pop	es:[di].pcb32.regcs
		mov	es:[di].pcb32.regsp, sp
		mov	es:[di].pcb32.regss, ss

		mov	bx, es			;Save so we can return in
		mov	ecx, edi		; ES:DI later.
		mov	edx, es:[di].pcb32.regedi
		mov	es, es:[di].pcb32.reges
		mov	di, dx			;Point es:di at new PCB

		mov	wp dseg:CurCoroutine, di
		mov	wp dseg:CurCoroutine+2, es

		mov	es:[di].pcb32.regedi, ecx ;The ES:DI return values.
		mov	es:[di].pcb32.reges, bx

; Okay, switch to the new process:

		mov	ss, es:[di].pcb32.regss
		mov	sp, es:[di].pcb32.regsp
		mov	eax, es:[di].pcb32.regeax
		mov	ebx, es:[di].pcb32.regebx
		mov	ecx, es:[di].pcb32.regecx
		mov	edx, es:[di].pcb32.regedx
		mov	esi, es:[di].pcb32.regesi
		mov	ebp, es:[di].pcb32.regebp
		mov	ds, es:[di].pcb32.regds

		push	es:[di].pcb32.regflags
		push	es:[di].pcb32.regcs
		push	es:[di].pcb32.regip
		push	es:[di].pcb32.regedi
		mov	es, es:[di].pcb32.reges
		pop	edi
		iret
cocall32	endp


; CoCall32l works just like cocall above, except the address of the pcb
; follows the call in the code stream rather than being passed in ES:DI.
; Note: this code does *not* return the caller's PCB address in ES:DI.
;

cocall32l	proc	far
		assume	ds:dseg
		push	ebp
		mov	bp, sp
		pushfd
		push	ds
		push	es
		push	edi
		push	eax
		mov	ax, dseg
		mov	ds, ax
		cli				;Critical region ahead.

; Save the current process' state:

		les	di, dseg:CurCoroutine
		pop	es:[di].pcb32.regeax
		mov	es:[di].pcb32.regebx, ebx
		mov	es:[di].pcb32.regecx, ecx
		mov	es:[di].pcb32.regedx, edx
		mov	es:[di].pcb32.regesi, esi
		pop	es:[di].pcb32.regedi
		pop	es:[di].pcb32.reges
		pop	es:[di].pcb32.regds
		pop	es:[di].pcb32.regflags
		pop	es:[di].pcb32.regebp
		pop	es:[di].pcb32.regip
		pop	es:[di].pcb32.regcs
		mov	es:[di].pcb32.regsp, sp
		mov	es:[di].pcb32.regss, ss

		mov	dx, es:[di].pcb32.regip	;Get return address (ptr to
		mov	cx, es:[di].pcb32.regcs	; PCB address.
		add	es:[di].pcb32.regip, 4	;Skip ptr on return.
		mov	es, cx			;Get the ptr to the new pcb
		mov	di, dx			; address, then fetch the
		les	di, es:[di]		; pcb val.
		mov	wp dseg:CurCoroutine, di
		mov	wp dseg:CurCoroutine+2, es

; Okay, switch to the new process:

		mov	ss, es:[di].pcb32.regss
		mov	sp, es:[di].pcb32.regsp
		mov	eax, es:[di].pcb32.regeax
		mov	ebx, es:[di].pcb32.regebx
		mov	ecx, es:[di].pcb32.regecx
		mov	edx, es:[di].pcb32.regedx
		mov	esi, es:[di].pcb32.regesi
		mov	ebp, es:[di].pcb32.regebp
		mov	ds, es:[di].pcb32.regds

		push	es:[di].pcb32.regflags
		push	es:[di].pcb32.regcs
		push	es:[di].pcb32.regip
		push	es:[di].pcb32.regedi
		mov	es, es:[di].pcb32.reges
		pop	edi
		iret


cocall32l	endp
cseg		ends
		end