*
* This is a copy of c.a, distributed with the Lattice 5.04 compiler, that has
*	been hacked to support my LaunchChild calls. There is no WorkBench
*	support in this startup.
*
*					Ray
*
*
* C initial startup procedure under AmigaDOS
* 
* Use the following command line to make c.o
* asm -u -iINCLUDE: c.a
*
* Use the following command line to make cres.o
* asm -u -dRESIDENT -iINCLUDE: -ocres.o c.a
*
	INCLUDE	"exec/types.i"
	INCLUDE	"exec/alerts.i"
	INCLUDE	"exec/nodes.i"
	INCLUDE	"exec/lists.i"
	INCLUDE	"exec/ports.i"
	INCLUDE	"exec/libraries.i"
	INCLUDE	"exec/tasks.i"
	INCLUDE	"exec/memory.i"
	INCLUDE	"exec/execbase.i"
	INCLUDE	"libraries/dos.i"
	INCLUDE	"libraries/dosextens.i"
	INCLUDE	"exec/funcdef.i"
	INCLUDE	"exec/exec_lib.i"
	INCLUDE	"libraries/dos_lib.i"

MEMFLAGS	EQU	MEMF_CLEAR+MEMF_PUBLIC
AbsExecBase	EQU	4

; some usefull macros:

callsys macro
	CALLLIB _LVO\1
	endm
	
	xdef	_XCEXIT		* exit(code) is standard way to leave C.
	xdef	_@XCEXIT
	
	xref	_LinkerDB	* linker defined base value
	xref	__BSSBAS	* linker defined base of BSS
	xref	__BSSLEN	* linker defined length of BSS
	IFD	RESIDENT
	xref	_RESLEN
	xref	_RESBASE
	xref	_NEWDATAL
	xref	__stack
	ENDC
	
*	library references

	section text,code

	xref	__xmain			* Name of C program to start with.
	xref	_MemCleanup		* Free all allocated memory
	xref	___fpinit		* initialize floating point
	xref	___fpterm		* terminate floating point
	
start:
	movem.l d1-d6/a0-a6,-(a7)

	move.l	a0,a2			* save command pointer
	move.l	d0,d2			* and command length
	lea	_LinkerDB,a4		* load base register
	move.l	AbsExecBase.W,a6

*------ are we running as a son of Workbench?
	move.l	ThisTask(a6),A3
	tst.l	pr_CLI(A3)
	bne.s	fromCLI
	
*=======================================================================
*====== Workbench Startup Code =========================================
*=======================================================================

fromWorkbench:

	lea	pr_MsgPort(A3),a0	* our process base
	callsys WaitPort
	lea	pr_MsgPort(A3),a0	* our process base
	callsys GetMsg
	move.l	d0,a2

*$* should put recoverable alert here

*------	return the startup message to our parent
*	we forbid so workbench can't UnLoadSeg() us
*	before we are done:
	callsys	Forbid
	move.l	a2,a1
	callsys	ReplyMsg

	moveq.l	#-1,D0
	
	movem.l (a7)+,d1-d6/a0-a6
	rts
	
*=======================================================================
*====== CLI Startup Code ===============================================
*=======================================================================

fromCLI:
	IFND	RESIDENT
		lea	__BSSBAS,a3		* get base of BSS
		moveq	#0,d1
		move.l	#__BSSLEN,d0		* get length of BSS in longwords
		bra.s	clr_lp			* and clear for length given
clr_bss		move.l	d1,(a3)+
clr_lp		dbf	d0,clr_bss
		move.l	a7,__StackPtr(A4)	* Save stack ptr
		move.l	a6,_SysBase(A4)
	ENDC
	

	IFD	RESIDENT
		movem.l	d2,-(a7)
		movem.l a0-a2,-(a7)

*------		get the size of the stack, if CLI use cli_DefaultStack

		move.l	ThisTask(a6),A3
		move.l	pr_CLI(A3),d1
		lsl.l	#2,d1
		move.l	d1,a0
		move.l	cli_DefaultStack(a0),d1
		lsl.l	#2,d1			* # longwords -> # bytes

dostack:
		moveq	#0,d2			* use d2 as flag for newstack or not
		move.l	#RESLEN,d0
		cmp.l	__stack(a4),d1		* This a4 is in the original 
						* set of data
		bcc.s	nochange	
		move.l	__stack(a4),d1
		add.l	d1,d0			* increase size of mem for new stack
		moveq	#1,d2			* set flag
		
nochange:
		move.l	d1,a3			* save stacksize to set up stack checking
		move.l	#MEMFLAGS,d1
		callsys AllocMem
		tst.l	d0
		bne.s	ok1
		movem.l	(a7)+,d2/a0-a2
*$* ACK!!!
*$*		rts
*$* ACK!!!

ok1:		move.l	d0,a0
		move.l	d0,a2

	;a2 now has difference
		move.l	d0,a1
		move.l	#NEWDATAL,d0
		sub.l	#RESBASE,a4
	;copy data over
cpy:		move.l	(a4)+,(a0)+
		subq.l	#1,d0
		bne.s	cpy
	;a4 now points at number of relocs
		move.l	(a4)+,d0
reloc:		beq.s	nreloc
		move.l	a1,a0
		add.l	(a4)+,a0		* a0 now has add of reloc
		add.l	(a0),a2
		move.l	a2,(a0) 
		move.l	a1,a2			* restore offset
		subq.l	#1,d0
		bra.s	reloc

nreloc:		move.l	a1,a4			* set up new base register
		add.l	#RESBASE,a4

		move.l	#RESLEN,realdatasize(a4)
		movem.l (a7)+,a0-a2

		move.l	a6,_SysBase(A4)
		tst.b	d2
		movem.l	(a7)+,d2		* restore d2 
		movem.l a7,__StackPtr(A4)	* Save stack ptr (movem doesn't
						* change flags
		beq.s	nochg2

*------		set up new stack
		move.l	a4,d0
		sub.l	#RESBASE,d0
		add.l	#RESLEN,d0
		add.l	__stack(a4),d0		* here a4 will be pointing at the
						* new data, but _stack will be the
						* same if all goes well

		sub.l	#128,d0			* 128 down for good measure
		move.l	d0,a7
		move.l	__stack(a4),d0
		move.l	d0,4(a7)		* fill in size of new stack	
		add.l	d0,_realdatasize(a4) 	* need to know how much to free later

nochg2:
*------		Set _base for stack checking
		move.l	a7,d1
		sub.l	a3,d1			* get top of stack
		add.l	#128,D1			* allow for parms overflow
		move.l	D1,__base(A4)		* save for stack checking

	ENDC

clrwb:
	clr.l	_WBenchMsg(A4)

*-----	clear any pending signals
	moveq	#0,d0
	move.l	#$00003000,d1
	callsys	SetSignal
	

*------ attempt to open DOS library:
	lea	DOSName(PC),A1
	moveq.l #0,D0
	callsys OpenLibrary
	move.l	D0,_DOSBase(A4)
	bne.s	ok2
	moveq.l #100,d0
	bra.w	exit2

ok2:
*=======================================================================
*
* Entry: D2 = command length
*	A2 = Command pointer

	ifnd	RESIDENT		* we need to set _base if not resident
		move.l	a7,D0		* get top of stack
		sub.l	4(a7),D0	* compute bottom 
		add.l	#128,D0		* allow for parms overflow
		move.l	D0,__base(A4)	* save for stack checking
	endc
	
*------ find command name:
	move.l	ThisTask(a6),A3
	move.l	pr_CLI(a3),a0
	add.l	a0,a0		* bcpl pointer conversion
	add.l	a0,a0
	move.l	cli_CommandName(a0),a1
	add.l	a1,a1		* bcpl pointer conversion
	add.l	a1,a1

*------ collect parameters:
	move.b	(a1)+,d0
	move.l	a1,__ProgramName(A4)


	move.l	d2,-(A7)		* push command line length
	move.l	a2,-(A7)		* push command line address

*=============================================
*------ common code --------
*=============================================

main	jsr	___fpinit(PC)		* Initialize floating point
	jsr	__xmain(PC)		* call C entrypoint
	moveq.l	#0,d0			* set successful status
	bra.s	exit2
*

_XCEXIT:
	move.l	4(SP),d0		* extract return code
_@XCEXIT:
exit2:
	move.l	d0,-(a7)
	move.l	__ONEXIT(A4),d0		* exit trap function?
	beq.s	 exit3
	move.l	d0,a0
	jsr	(a0)
exit3	move.l	__Children(a4),d0	* if we have any children
	beq.s	exit4			*	orphan them
	move.l	d0,a0
	move.l	(a0),a0
	jsr	(a0)
exit4	jsr	_MemCleanup(PC)		* cleanup leftover memory alloc.
	move.l	AbsExecBase.W,a6
	move.l	_DOSBase(A4),a1
	callsys CloseLibrary		* close Dos library

	jsr	___fpterm(PC)		* clean up any floating point

*------ this rts sends us back to DOS:
exitToDOS:
	IFD	RESIDENT
		move.l	realdatasize(a4),d0
		move.l	a4,a1
		sub.l	#RESBASE,a1
		move.l	AbsExecBase.W,a6
		move.l	(A7)+,d6
		movea.l	__StackPtr(a4),a5
		callsys	FreeMem
		move.l	d6,d0
		movea.l	a5,sp
	ELSE
		move.l	(A7)+,D0
		movea.l	__StackPtr(a4),SP	* restore stack ptr
	ENDC
	
	movem.l (a7)+,d1-d6/a0-a6
	rts


DOSName	 dc.b	'dos.library',0

	section __MERGED,BSS
*
	xref	_DOSBase

	xdef	_NULL,_SysBase,_WBenchMsg
	xdef	_curdir,__mbase,__mnext,__msize,__tsize
	xdef	__oserr,__OSERR,__FPERR,__SIGFPE,__ONERR,__ONEXIT,__ONBREAK
	xdef	__SIGINT
	xdef	__ProgramName,__StackPtr,__base
	xdef	__Children

*
	ifd	RESIDENT
realdatasize	ds.l	1	* size of memory allocated for data +
				* possible stack
	endc
	
_NULL		ds.l	1	*
__base		ds.l	1	* base of stack
__mbase		ds.l	1	* base of memory pool
__mnext		ds.l	1	* next available memory location
__msize		ds.l	1	* size of memory pool
__tsize		ds.l	1	* total size?
__oserr		equ	*
__OSERR		ds.l	1
__FPERR		ds.l	1
__SIGFPE	ds.l	1
__SIGINT	ds.l	1
__ONERR		ds.l	1
__ONEXIT	ds.l	1
__ONBREAK	ds.l	1
_curdir	 	ds.l	1
_SysBase	ds.l	1
_WBenchMsg	ds.l	1
__StackPtr	ds.l	1
stdin		ds.l	1
__ProgramName	ds.l	1
__Children	ds.l	1
		END
