	title INIT - Initialization routines

	.286p

NX	equ	4		; for near calls
FX	equ	6		; for far calls

CONST	SEGMENT WORD PUBLIC 'CONST'
CONST	ENDS
_DATA	SEGMENT WORD PUBLIC 'DATA'
_DATA	ENDS
_BSS	SEGMENT WORD PUBLIC 'BSS'
_BSS	ENDS

STACK	SEGMENT WORD STACK 'STACK'
	ALIGN	16
	PUBLIC	mystack, estack
mystack	db	800h dup (?)
estack	dw	0
; You're probably wondering why I didn't just say:
; estack	label	word
; on the line above.  The reason I initialized part of the STACK segment
; is to make the linker create a big file with all of STACK and BSS.
; The reason for this is that overlays don't allocate memory based on the
; MINALLOC value in the .EXE file.
STACK	ENDS

DGROUP	GROUP	CONST,_DATA,_BSS

_TEXT	SEGMENT WORD PUBLIC 'CODE'
	EXTRN	__astart:FAR
_TEXT	ENDS

_DATA	SEGMENT
	PUBLIC	nums
nums	db	'0123456789abcdef'
; Make sure these are not zeroed with the rest of BSS in the C startup code.
savesp	dw	0
savess	dw	0
_DATA	ENDS

_BSS	SEGMENT
pstack	dw	?
	PUBLIC	n_buf
n_buf	db	6 dup (?)
_BSS	ENDS

	ASSUME cs:_TEXT, ds:nothing, es:nothing, ss:nothing

_TEXT	SEGMENT
	EXTRN	_rpc_entry:NEAR

my_psp	db	0100h dup (?)

	PUBLIC	@leave
_init_rpc	PROC	FAR
	; Call the C startup code __astart.  The trouble is that __astart
	; will call _exit after _main.  To solve that problem we save our
	; stack and have _main jump back to here.

	mov	ax,DGROUP
	mov	ds,ax
	ASSUME	ds:DGROUP

	; save the current stack pointer to we can use it to return
	; from this procedure in @leave, below.
	mov	savess,ss
	mov	savesp,sp

	; Get our PSP for environment, etc.
	mov	ah,62h	; get PSP
	int	21h
	mov	ds,bx	; PSP segment
	ASSUME	ds:nothing

	mov	ax,_TEXT
	; The first thing in the _TEXT segment always starts at 10h,
	; so incrementing the PSP segment by one will point us to my_psp
	inc	ax
	mov	es,ax
	ASSUME	es:nothing
	xor	si,si
	xor	di,di
	mov	cx,80h		; PSP is 80 words long
	rep	movsw

	; Now update the word at location 02.  This is the top of the
	; allocated memory and we know what that should be.
	mov	ax,offset DGROUP:estack
	shr	ax,4
	mov	ax,DGROUP
	mov	es:[02],ax

	; The C routine __astart expects DS and ES to point to the PSP.
	; It also wants SP to point to the end of the stack segment.
	mov	ax,es
	mov	ds,ax
	mov	ax,STACK
	mov	ss,ax
	mov	sp,offset STACK:estack

	call	__astart
	; NOTREACHED
	ret
@leave:
	ASSUME	ds:DGROUP

	mov	pstack,sp
	mov	ss,savess
	mov	sp,savesp
	xor	cx,cx
	iret
_init_rpc	ENDP

	; __fptrap is called by __cinit if __fpinit fails.  I really don't
	; know what to do in this case, but it shouldn't happen anyway.
	; Returning from this will cause __cinit to return.
	PUBLIC	__fptrap
__fptrap	PROC FAR
	ret
__fptrap	ENDP

	; real procedure entry point
	; called from MicroX with:
	; AX	= function
	; BX	= arg
	; CX	= size of buffer
	; DS:0 = transaction buffer
	; return AX = return value
	;	 BX = neterrno
	;	 CX = errno or bytes returned
	;
	; push this stuff on the stack and call the C routine.
	ASSUME	ds:nothing
p_rpc		PROC	FAR
	or	ax,ax
	jne	rpc1
	jmp	short _init_rpc

rpc1:
	push	si
	push	es
	mov	si,ax		; save function
	mov	ax,ds
	mov	es,ax		; save buffer
	mov	ax,DGROUP
	mov	ds,ax
	ASSUME	ds:DGROUP

	; setup my stack
	mov	savess,ss
	mov	savesp,sp
	mov	ss,ax
	mov	sp,pstack

	push	es
	push	word ptr 0	; buffer
	push	cx		; len
	push	bx		; arg
	push	si		; func
	call	_rpc_entry
	add	sp,2		; don't pop ax
	pop	bx
	pop	cx		; data modified on stack by C routine
	add	sp,4		; buffer

	; restore our stack
	mov	ss,savess
	mov	sp,savesp

	pop	es
	pop	si

	iret
p_rpc		ENDP

	ASSUME	ds:DGROUP

	PUBLIC	@dfputs
; void _fastcall dfputs(cp)
; char near *cp;
@dfputs	PROC NEAR
	push	si
	mov	si,bx
	mov	ah,2
put_loop:
	lodsb
	or	al,al
	jz	put_exit
	mov	dl,al
	int	21h
	jmp	short put_loop
put_exit:
	pop	si
	ret
@dfputs	ENDP

	PUBLIC	@printn
@printn PROC NEAR
	xor	bl,bl
	mov	n_buf+4,bl
	mov	bx,ax
	and	bx,0fh
	mov	bl,nums[bx]
	mov	n_buf+3,bl
	shr	ax,4
	mov	bx,ax
	and	bx,0fh
	mov	bl,nums[bx]
	mov	n_buf+2,bl
	shr	ax,4
	mov	bx,ax
	and	bx,0fh
	mov	bl,nums[bx]
	mov	n_buf+1,bl
	shr	ax,4
	mov	bx,ax
	and	bx,0fh
	mov	bl,nums[bx]
	mov	n_buf,bl
	lea	bx,n_buf
	jmp	short @dfputs
@printn	ENDP

	PUBLIC	@printd
@printd PROC NEAR
	lea	bx,n_buf+5
	xor	cl,cl
	mov	[bx],cl
	mov	cx,10		; divide by 10
pd_1:
	xor	dx,dx		; divide number by 10
	div	cx
	add	dx,'0'		; remainder is in dx
	dec	bx
	mov	[bx],dl
	or	ax,ax
	jnz	pd_1		; more to divide
	jmp	short @dfputs
@printd	ENDP

_TEXT	ENDS
	END	p_rpc
