*
* C initial startup procedure under AmigaDOS
* Adapted by Jorrit Tyberghein
* 
* Use the following command line to make the cli/workbench startup
* asm -iINCLUDE: Arg.asm
*
* Use the following command line to make the resident startup
* asm -dRESIDENT -iINCLUDE: -oArgR.o Arg.asm
*
* Use the following command line to make the cli startup
* asm -dCLI -iINCLUDE: Arg.asm
*
	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	"workbench/startup.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		_argmain				* Name of C program to start with.
	
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

	IFND RESIDENT
;We do not have to clear BSS because AmigaDOS 2.0 does this for us.
;		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
*------										if WB use a7 - TC_SPLOWER
		move.l	ThisTask(a6),A3
		move.l	pr_CLI(A3),d1
	IFND CLI
		beq.s		fromwb
	ENDC
		lsl.l		#2,d1
		move.l	d1,a0
		move.l	cli_DefaultStack(a0),d1
		lsl.l		#2,d1					* # longwords -> # bytes
	IFND CLI
		bra.s		dostack
fromwb:
		move.l	a7,d1		 	
		sub.l		TC_SPLOWER(a3),d1 	
	ENDC
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
		rts

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:

	ENDC

clrwb:
	IFND CLI
		clr.l		_WBenchMsg(A4)
	ENDC

*-----  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:
*------ are we running as a son of Workbench?
		move.l	ThisTask(a6),A3
	IFND CLI
		tst.l		pr_CLI(A3)
		beq.s		fromWorkbench
	ENDC
	
*=======================================================================
*====== CLI Startup Code ===============================================
*=======================================================================
*
* Entry: D2 = command length
*			A2 = Command pointer
fromCLI:
	
*------ find command name:
		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.l	d2,d0					* get command line length
		moveq.l	#0,d1
		move.b	(a1)+,d1
		move.l	a1,_ProgramName(A4)
		add.l		d1,d0					* add length of command name
		addq.l	#1,d0					* allow for space after command 

		clr.w		-(A7)					* set null terminator for command line
		addq.l	#3,D0					* force to longword alligned number of bytes
		andi.w	#$fffc,D0			* (round up)
		addq.l	#2,d0					* one extra word
		sub.l		D0,A7					* make room on stack for command line
		subq.l	#6,D0
		clr.l		0(A7,D0)

*------ copy command line onto stack
		move.l	d2,d0					* get command line length
		subq.l	#1,d0
		add.l		d1,d2

copy_line:
		move.b	0(A2,D0.W),0(A7,D2.W)	* copy command line to stack
		subq.l	#1,d2
		dbf		d0,copy_line
		move.b	#' ',0(a7,d2.w)	* add space between command and parms
		subq.l	#1,d2

copy_cmd:
		move.b	0(a1,d2.w),0(a7,d2.w)	* copy command name to stack
		dbf		d2,copy_cmd
		move.l	A7,A1
		move.l	A1,-(A7)				* push command line address
	IFND CLI
		bra.s		main					* call C entrypoint

*=======================================================================
*====== Workbench Startup Code =========================================
*=======================================================================

fromWorkbench:

*------ we are now set up.  wait for a message from our starter
		lea		pr_MsgPort(A3),a0	* our process base
		callsys	WaitPort
		lea		pr_MsgPort(A3),a0	* our process base
		callsys	GetMsg
		move.l	d0,_WBenchMsg(a4)
		move.l	d0,-(SP)
*
		move.l	d0,a2					* get first argument
		move.l	sm_ArgList(a2),d0
		beq.s		do_cons
		move.l	_DOSBase(a4),a6
		move.l	d0,a0
		move.l	wa_Lock(a0),d1
		callsys	CurrentDir
do_cons:
		move.l	sm_ToolWindow(a2),d1	* get the window argument
		beq.s		do_main
		move.l	#MODE_OLDFILE,d2
		callsys	Open
		move.l	d0,stdin(a4)
		beq.s		do_main
		lsl.l		#2,d0
		move.l	d0,a0
		move.l	fh_Type(a0),pr_ConsoleTask(A3)
do_main:
		move.l	_WBenchMsg(A4),a0	* get address of workbench message
		move.l	a0,-(a7)				* push argv
		moveq		#0,d0
		move.l	d0,-(a7)				* push argc
		move.l	sm_ArgList(a0),a0	* get address of arguments
		move.l	wa_Name(a0),_ProgramName(A4)	* get name of program
	ENDC

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

main
		jsr		_argmain(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	AbsExecBase.W,a6
		move.l	_DOSBase(A4),a1
		callsys	CloseLibrary		* close Dos library

done_1c:
*------ if we ran from CLI, skip workbench cleanup:
	IFND CLI
		tst.l		_WBenchMsg(A4)
		beq.s		exitToDOS
		move.l	stdin(a4),d1
		beq.s		done_4
		callsys	Close
done_4:

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

*------ 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
*
		xdef		_SysBase,_WBenchMsg
		xdef		_ProgramName,__StackPtr,_DOSBase

*
	ifd RESIDENT
realdatasize
		ds.b		4						* size of memory allocated for data +
											* possible stack
	endc

_SysBase			ds.b	4
_WBenchMsg		ds.b	4
__StackPtr		ds.b	4
stdin				ds.b	4
_DOSBase			ds.b	4
_ProgramName	ds.b	4
		END
