; register.asm - routines to save and restore the register values for
;                use in conjunction with thread.c
;
; Programmer   - E.J.Pugh, FIAP
;
; Copyright    - (c) Edward James Pugh, June 1991

%       .MODEL  mem,pascal
	PUBLIC  Suspend, Resume

_AX     equ     0
_BX     equ     2
_CX     equ     4
_DX     equ     6
_ES     equ     8
_SP     equ     10
_BP     equ     12
_SI     equ     14
_DI     equ     16
_IP     equ     18
IF      @Model  eq      4       ; Medium model
_PS     equ     20
_DS     equ     0
ELSEIF  @Model  eq      3       ; Compact model
_PS     equ     0
_DS     equ     20
ELSEIF  @Model  eq      2       ; Small Model
_PS     equ     0
_DS     equ     0
ELSEIF  @Model  eq      1       ; Tiny model
_PS     equ     0
_DS     equ     0
ELSE                            ; Large or Huge model
_PS     equ     20
_DS     equ     22
ENDIF


savewregs       MACRO
		IF      @Datasize
		mov     axReg, ax
		mov     bxReg, bx
		mov     ax, es
		mov     esReg, ax
		ELSE
		mov     bxReg, bx
		ENDIF
		ENDM
getreturn       MACRO
		IF      @Codesize
		pop     RetOff
		pop     RetSeg
		ELSE
		pop     RetOff
		ENDIF
		ENDM
getargument     MACRO
		IF      @Datasize
		pop     bx
		pop     es
		ELSE
		pop     bx
		ENDIF
		ENDM
storereturn     MACRO
		IF      @Codesize
			IF      @Datasize
			push    RetOff
			pop     es:[bx]._IP
			push    RetSeg
			pop     es:[bx]._PS
			ELSE
			push    RetOff
			pop     [bx]._IP
			push    RetSeg
			pop     [bx]._PS
			ENDIF
		ELSE
			IF      @Datasize
			push    RetOff
			pop     es:[bx]._IP
			ELSE
			push    RetOff
			pop     [bx]._IP
			ENDIF
		ENDIF
		ENDM
storeregs       MACRO
		IF      @Datasize
		mov     ax, axReg
		mov     es:[bx]._AX, ax
		mov     ax, bxReg
		mov     es:[bx]._BX, ax
		mov     es:[bx]._CX, cx
		mov     es:[bx]._DX, dx
		mov     ax, esReg
		mov     es:[bx]._ES, ax
		mov     es:[bx]._SP, sp
		mov     es:[bx]._BP, bp
		mov     es:[bx]._SI, si
		mov     es:[bx]._DI, di
		mov     ax, RetOff
		mov     es:[bx]._IP, ax
		mov     ax, ds
		mov     es:[bx]._DS, ax
			IF      _PS
			mov     ax, RetSeg
			mov     es:[bx]._PS, ax
			ENDIF
		ELSE
		mov     [bx]._AX, ax
		mov     ax, bxReg
		mov     [bx]._BX, ax
		mov     [bx]._CX, cx
		mov     [bx]._DX, dx
		mov     ax, es
		mov     [bx]._ES, ax
		mov     [bx]._SP, sp
		mov     [bx]._BP, bp
		mov     [bx]._SI, si
		mov     [bx]._DI, di
		mov     ax, RetOff
		mov     [bx]._IP, ax
			IF      _PS
			mov     ax, RetSeg
			mov     [bx]._PS, ax
			ENDIF
		ENDIF
		ENDM
putreturn       MACRO
		IF      @Codesize
		push    RetSeg
		push    RetOff
		ELSE
		push    RetOff
		ENDIF
		ENDM
reswregs        MACRO
		IF      @Datasize
		mov     ax, esReg
		mov     es, ax
		mov     bx, bxReg
		mov     ax, axReg
		ELSE
		mov     bx, bxReg
		ENDIF
		ENDM
setstack        MACRO
		IF      @Datasize
		mov     sp, es:[bx]._SP
		ELSE
		mov     sp, [bx]._SP
		ENDIF
		ENDM
putoldreturn    MACRO
		IF      @Codesize
			IF      @Datasize
			mov     ax, es:[bx]._PS
			push    ax
			mov     ax, es:[bx]._IP
			push    ax
			ELSE
			push    [bx]._PS
			push    [bx]._IP
			ENDIF
		ELSE
			IF      @Datasize
			mov     ax, es:[bx]._IP
			push    ax
			ELSE
			push    [bx]._IP
			ENDIF
		ENDIF
		ENDM
loadregs        MACRO
		IF      @Datasize
		mov     cx, es:[bx]._CX
		mov     dx, es:[bx]._DX
		mov     bp, es:[bx]._BP
		mov     si, es:[bx]._SI
		mov     di, es:[bx]._DI
		mov     ax, es:[bx]._AX
		push    es:[bx]._DS
		push    es:[bx]._ES
		push    es:[bx]._BX
		pop     bx
		pop     es
		pop     ds
		ELSE
		mov     cx, [bx]._CX
		mov     dx, [bx]._DX
		mov     bp, [bx]._BP
		mov     si, [bx]._SI
		mov     di, [bx]._DI
		mov     ax, [bx]._ES
		mov     es, ax
		mov     ax, [bx]._AX
		mov     bx, es:[bx]._BX
		ENDIF
		ENDM

	.DATA

RetOff  dw      0       ; return offset storage for IP
IF      _PS
RetSeg  dw      0       ; poss return segment for PS
ENDIF
bxReg   dw      0       ; temporary bx storage
IF      _DS
esReg   dw      0       ; poss temporary es storage
axReg   dw      0       ; poss temporary ax storage
ENDIF



	.CODE
;--------------------------------------------------------------------------
; Suspend         -       Suspend

; Description     -       Saves the present register values and the return
;                         address in the supplied ThreadReg structure.

; Parameters      -       Suspend(registers)
;                         ThreadReg_t *registers;

; Returns         -       NOTHING.
;--------------------------------------------------------------------------
Suspend PROC
	savewregs       ; save working registers
	getreturn       ; pop return address from stack
	getargument     ; pop argument from stack
	storereturn     ; store return address in structure
	storeregs       ; store register values in structure
	putreturn       ; push return address back on stack
	reswregs        ; restore working register values
	ret             ; bye
Suspend ENDP

;--------------------------------------------------------------------------
; Resume          -       Resume

; Description     -       Cleans up the current stack, restores the register
;                         values contained in the supplied ThreadReg
;                         structure, places the stored address on the thread
;                         stack (accessed once SP and SS have been loaded)
;                         and executes a return.

; Parameters      -       Resume(target)
;                         ThreadReg_t *target; target process

;                         We use the pascal type calling convention because
;                         we do not want the calling routine to be responsible
;                         for cleaning up the stack.

; Returns         -       NOTHING. (Resume never returns to its caller)
;--------------------------------------------------------------------------
Resume  PROC
	getreturn       ; pop return address from stack (discard)
	getargument     ; pop argument from stack
	setstack        ; switch to thread stack
	putoldreturn    ; push stored return address to stack
	loadregs        ; load registers with stored values
	ret             ; bye
Resume  ENDP
	END
