The existing Standard Library (v1.0) coroutine package is not suitable for programs that use the 80386 and later 32 bit register sets. As mentioned earlier, the problem lies in the fact that the Standard Library only preserves the 16-bit registers when switching between processes. However, it is a relatively trivial extension to modify the Standard Library so that it saves 32 bit registers. To do so, just change the definition of the pcb
(to make room for the 32 bit registers) and the sl_cocall
routine:
.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