*
* 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

	IDNT	"c2.a"

	OPTION	L
	LISTSYMS
	BASEREG	B
	SMALLOBJ
	OPTIMON
	ADDSYM
	DEBUG

* --------------------------------------------------------------------- *
* Macros:
* --------------------------------------------------------------------- *
SYS	MACRO	*
	IFGT	NARG-2
	FAIL	!!!
	ENDC
	IFEQ	NARG-2
	MOVE.L	\2,a6
	ENDC
	JSR	_LVO\1(a6)
	ENDM

XLVO	MACRO	*
	XREF	_LVO\1
	ENDM

* --------------------------------------------------------------------- *
* Equates:
* --------------------------------------------------------------------- *
RESIDENT	EQU	1

MEMF_PUBLIC	EQU	$1
MEMF_CLEAR	EQU	$10000
MEMFLAGS	EQU	MEMF_CLEAR+MEMF_PUBLIC
AbsExecBase	EQU	$0004
cli_CommandName	EQU	$10
pr_CLI		EQU	$AC
pr_CurrentDir	EQU	$98
ThisTask	EQU	$114

_LVOCloseLibrary EQU	$FE62
_LVOAllocMem	EQU	$FF3A
_LVOFreeMem	EQU	$FF2E
_LVOSetSignal	EQU	$FECE
_LVOOpenLibrary	EQU	$FDD8

	XREF	_DOSBase
	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
	 ENDC
	
	XREF	__main			; Name of C program to start with.
	XREF	_MemCleanup		; Free all allocated memory
	XREF	___fpinit		; initialize floating point
	XREF	___fpterm		; terminate floating point

* --------------------------------------------------------------------- *
	SECTION	TEXT,CODE
* --------------------------------------------------------------------- *
	XDEF	zzstart
zzstart:
	move.l	a0,a2			; save command pointer
	move.l	d0,d2			; and command length
	lea	_LinkerDB,a4		; load base register

	 IFND	RESIDENT
	lea	__BSSBAS,a3		; get base of BSS
	moveq	#0,d1
	move.l	#__BSSLEN,d0		; get length of BSS in longwords
	 bra.b	clr_lp		 	; and clear for length given
clr_bss move.l	d1,(a3)+
clr_lp	dbf	d0,clr_bss
	 ENDC

	 IFD	RESIDENT
	movea.l	AbsExecBase,a6

	movem.l	d0-d1/a0-a2,-(sp)
	sub.l	#_RESBASE,a4
	move.l	#_RESLEN,d0
	move.l	#MEMFLAGS,d1
	SYS	AllocMem
	tst.l	d0
	 beq.w	abort
	move.l	d0,a0
	move.l 	d0,a2

;a2 now has difference
	move.l	d0,a1
	move.l	#_NEWDATAL,d0
;copy data over
cpy:	move.l	(a4)+,(a0)+
	subq.l	#1,d0
	 bne	cpy
;a4 now points at number of relocs
	move.l	(a4)+,d0
reloc:	 beq.b	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	reloc
	
nreloc: move.l	a1,a4			; set up new base register
	add.l	#_RESBASE,a4
	movem.l	(sp)+,d0-d1/a0-a2
	 ENDC

	movea.l	AbsExecBase,a6
	move.l	a6,_SysBase(a4)
	move.l	sp,__StackPtr(a4)	; Save stack ptr
	clr.l	_WBenchMsg(a4)

* get the address of our task
	move.l	ThisTask(a6),a3

*-	clear any pending signals
	moveq	#0,d0
	move.l	#$00003000,d1
	SYS	SetSignal
	
* are we running as a son of Workbench?
	move.l	pr_CurrentDir(a3),_curdir(a4)

	IFD	WBENCH
	tst.l	pr_CLI(a3)
	 beq	fromWorkbench
	ENDC

*=======================================================================
*====== CLI Startup Code ===============================================
*=======================================================================
*
; Entry: d2 = command length
;	 a2 = Command pointer
fromCLI:
	move.l	sp,d0		 	; get top of stack
	sub.l	4(sp),d0		; compute bottom 
	add.l	#128,d0	 		; allow for parms overflow
	move.l	d0,__base(a4)		; save for stack checking

* attempt to open DOS library:
	bsr.w	openDOS

* 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	-(sp)			; set null terminator for command line
	addq.l	#1,d0			; force to even number of bytes
	andi.w	#$fffe,d0		; (round up)
	sub.l	d0,sp			; make room on stack for command line
	subq.l	#2,d0
	clr.w	0(sp,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(sp,d2.w)	; copy command line to stack
	subq.l	#1,d2
	dbf	d0,copy_line
	move.b	#' ',0(sp,d2.w)	 	; add space between command and parms
	subq.l	#1,d2

copy_cmd:
	move.b	0(a1,d2.w),0(sp,d2.w)	; copy command name to stack
	dbf	d2,copy_cmd
	move.l	sp,a1
	move.l	a1,-(sp)		; push command line address

	IFD	WBENCH
	bra	main			; call C entrypoint
* --------------------------------------------------------------------- *
* Workbench Startup Code
* --------------------------------------------------------------------- *
fromWorkbench:
	move.l	TC_SPLOWER(a3),__base(a4) ; set base of stack
	moveq 	#127,d0
	addq.l	#1,d0			; Efficient way of getting in 128
	add.l	d0,__base(a4)		; allow for parms overflow

* open the DOS library:
	bsr.w	openDOS

* we are now set up. wait for a message from our starter
	lea	pr_MsgPort(a3),a0	; our process base
	SYS	WaitPort
	lea	pr_MsgPort(a3),a0	; our process base
	SYS	GetMsg
	move.l	d0,_WBenchMsg(a4)
	move.l	d0,-(sp)

	move.l	d0,a2			; get first argument
	move.l	sm_ArgList(a2),d0
	 beq	do_cons
	move.l	_DOSBase(a4),a6
	move.l	d0,a0
	move.l	wa_Lock(a0),d1
	move.l	d1,_curdir(a4)
	SYS	CurrentDir
do_cons:
	move.l	sm_ToolWindow(a2),d1	; get the window argument
	 beq	do_main
	move.l	#MODE_OLDFILE,d2
	SYS	Open
	move.l	d0,_stdin(a4)
	 beq	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,-(sp)		; push argv
	pea	_NULL(a4)		; 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 CLI/WBENCH code
* --------------------------------------------------------------------- *
main:
	 IFD	FLOAT
	jsr	___fpinit(pc)		; Initialize floating point
	 ENDC
	jsr	__main(pc)		; call C entrypoint
	moveq.l	#0,d0			; set successful status
	bra.b	exit2

	XDEF	_XCEXIT
_XCEXIT:
	move.l	4(sp),d0		; extract return code

	XDEF	xXCEXIT
xXCEXIT:
exit2:
	 IFD	ERRTRAPS
	move.l	d0,-(sp)
	move.l	__ONEXIT(a4),d0		; exit trap function?
	 beq.b	exit3
	move.l	d0,a0
	jsr	(a0)
exit3:
	 ENDC

	 IFD	MALLOC
	jsr	_MemCleanup(pc)		; cleanup leftover memory alloc.
	 ENDC

	movea.l	AbsExecBase,a6
	move.l	_DOSBase(a4),a1
	SYS	CloseLibrary		; close Dos library

	 IFD	FLOAT
	jsr	___fpterm(pc)		; clean up any floating point
	 ENDC

	 IFD	WBENCH
done_1c:
* if we ran from CLI, skip workbench cleanup:
	tst.l	_WBenchMsg(a4)
	 beq	exitToDOS
	move.l	_stdin(a4),d1
	 beq.b	done_4
	SYS	Close
done_4:
* return the startup message to our parent
*	 we forbid so workbench can't UnLoadSeg() us
*	 before we are done:
	movea.l	AbsExecBase,a6
	SYS	Forbid
	move.l 	_WBenchMsg(a4),a1
	SYS	ReplyMsg
	 ENDC

* this rts sends us back to DOS:
exitToDOS:
	 IFD	RESIDENT
	move.l	#_RESLEN,d0
	move.l 	a4,a1
	sub.l	#_RESBASE,a1
	movea.l	AbsExecBase,a6
	SYS	FreeMem
	 ENDC
	
	move.l	(sp)+,d0
	movea.l	__StackPtr(a4),sp	; restore stack ptr

	XDEF	xchkabort
xchkabort:
	rts

	 IFD	RESIDENT
abort:
	movem.l	(sp)+,d0-d1/a0-a2
	rts
	 ENDC

* --------------------------------------------------------------------- *
noDOS:
	moveq.l	#100,d0
	bra	exit2

* --------------------------------------------------------------------- *
*	Open the DOS library:
* --------------------------------------------------------------------- *
openDOS:
	lea	DOSName(pc),a1
	moveq.l #0,d0
	SYS	OpenLibrary
	move.l	d0,_DOSBase(a4)
	 beq	noDOS
	rts

DOSName:	dc.b	'dos.library',0

* --------------------------------------------------------------------- *
	section __MERGED,BSS
* --------------------------------------------------------------------- *

	XDEF	_NULL,_SysBase,_WBenchMsg
	XDEF	_curdir,__mbase,__mnext,__msize,__tsize
	XDEF	__oserr,__OSERR
	 IFD	FLOAT
	XDEF	__FPERR
	XDEF	__SIGFPE
	 ENDC
	 IFD	ERRTRAPS
	XDEF	__ONERR,__ONEXIT,__ONBREAK
	XDEF	__SIGINT
	 ENDC
	XDEF	_stdin
	XDEF	__ProgramName,__StackPtr,__base

* --------------------------------------------------------------------- *
_NULL		ds.l	1		 ; Huh?
__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
__OSERR		ds.l	1
	 IFD	FLOAT
__FPERR		ds.l	1
__SIGFPE	ds.l	1
	 ENDC
	 IFD	ERRTRAPS
__SIGINT	ds.l	1
__ONERR		ds.l	1
__ONEXIT	ds.l	1
__ONBREAK	ds.l	1
	 ENDC
_curdir		ds.l	1
_SysBase	ds.l	1
_WBenchMsg	ds.l	1
__StackPtr	ds.l	1
_stdin		ds.l	1
__ProgramName	ds.l	1

* --------------------------------------------------------------------- *
	END
* --------------------------------------------------------------------- *
