*--------------------------------------------------------------------*
*	Startup-Code, der zum erzeugen residenter Programme mit dem
*	Manx Aztec 'C' Compiler dient.
*
*	Geschrieben von:	Olaf Barthel, MXM
*				Brabeckstraße 35
*				D-3000 Hannover 71
*
*				Bundesrepublik Deutschland
*
*				Z-Net: O.BARTHEL@A-Link-H
*				Fido:  Olaf Barthel@2:247/200
*				Sub:   olsen@veeble.uucp
*				UUCP:  olsen%veeble@horga.as.sub.org
*
*	Copyright (C) 1990 by MXM, all rights reserved.
*
*--------------------------------------------------------------------*
*
*	Mit Hilfe dieses Startup-Codes können Programme erzeugt
*	werden, die 100% reentrant sind. Es wird weder die
*	arp.library benötigt, noch muß das Programm über den exit()
*	Befehl beendet werden (siehe Lattice/SAS 'C').
*
*	Damit diese Routinen funktionieren können, müssen die
*	folgenden Bedingungen erfüllt sein:
*
*	1) Das Programm darf NICHT das Large Code/Large Data Modell
*	   benutzen.
*
*	2) Das Programm darf nicht aus mehreren Datensegmenten
*	   bestehen (Scattered loading).
*
*	Da vom Datensegment des Programmes eine Kopie erzeugt wird,
*	die sowohl initialisierte Daten, als auch nicht initialisierte
*	Daten (BSS, oder block storage segment) enthält, befinden
*	sich beide Datenarten immer im selben Speichertyp. Dies
*	ist auch der Normalfall. Es wird allerdings Rücksicht darauf
*	genommen, in welchem Speichertyp (Chip/Public) sich das
*	Datensegment befindet.
*
*	Wichtig! Ein Programm, das auf diese Weise resident gemacht
*	         werden kann, darf sich nicht über Detach.o?? vom
*	         startenden CLI abkoppeln, anderenfalls wird die
*	         Segmentliste des Programmes gelöscht und der nächste
*	         aufruf des Programmes geht ins Leere!
*
*	Wer in diesem Programm Fehler entdeckt, der informiere mich
*	bitte schnellstens darüber!
*
*--------------------------------------------------------------------*
*
*	Der Programmcode muß folgendermaßen erzeugt werden:
*
*	AS Resident.asm
*	CC <Programm.c>
*
*	LN <Programm.o> Resident.o -Lc
*
*--------------------------------------------------------------------*

	include	"exec/types.i"
	include	"exec/tasks.i"
	include	"exec/alerts.i"
	include	"exec/memory.i"
	include	"exec/execbase.i"
	include	"libraries/dosextens.i"

*--------------------------------------------------------------------*
*
*	Vom Rest des Programmes verwendete Makros.
*
*--------------------------------------------------------------------*

CALL	macro
	xref	_LVO\1
	jsr	_LVO\1(a6)
	endm

AbsExecBase	equ	(4).w

*--------------------------------------------------------------------*
*
*	Vom Programm verwendete statische Daten.
*
*--------------------------------------------------------------------*

	dseg

DosName:
	dc.b	'dos.library',0			; Name der dos.library

MemName:
	dc.b	'MXM',0				; Identifizierung des
						; kopierten Speichers

	public	__H1_org,__H1_end,__H2_org,__H2_end
	public	__savsp,_SysBase,_DOSBase

*--------------------------------------------------------------------*

	cseg

	entry	.begin

	public	.begin,_geta4,__main

	mc68881

*--------------------------------------------------------------------*
*
*	Dies ist der Einsprungpunkt des Programmes
*
*--------------------------------------------------------------------*

.begin
	move.l	sp,a3				; Stackpointer merken

	far	data
	lea	__H1_org+32766,a4		; Datenbasisregister setzen
	near	data

	lea	__H1_end,a1
	lea	__H2_org,a2

	cmp.l	a1,a2				; Small code/small data?
	bne	Error1				; Wohl weniger!

	movem.l	d0/a0,-(sp)			; Kommandozeile und Länge speichern

	lea	__H1_org,a1			; Wo liegt das Datensegment?
	move.l	AbsExecBase,a6			; SysBase

	CALL	TypeOfMem			; Speichertyp ermitteln

	bset	#MEMB_CLEAR,d0			; Speicher soll gelöscht werden
	bclr	#MEMB_FAST,d0			; Keinesfalls FastMem!

*--------------------------------------------------------------------*
*
*	Auf dem Stack wird eine MemEntry-Struktur erzeugt, in die
*	anschließend das Datensegment des Programmes kopiert wird.
*
*--------------------------------------------------------------------*

	pea	(__H2_end-__H1_org).w		; Länge des Datensegments
	move.l	d0,-(sp)			; Speichertyp
	pea	(1).w				; Anzahl der Einträge
	clr.l	-(sp)				; Node...
	clr.l	-(sp)				; Immer noch Node...
	clr.l	-(sp)				; Natürlich noch Node...

	lea	(sp),a0				; Anfang des Bereichs

	CALL	AllocEntry			; Beschaffen!

	add.w	#24,sp				; Stack korrigieren

	move.l	d0,a1				; MemEntry holen, erfolgreich?
	beq	Error2				; Stack korrigieren und raus!

	pea	(a1)				; Auf den Stack packen

*--------------------------------------------------------------------*
*
*	Zur leichteren Identifikation für geta4() erhält die
*	erzeugte MemEntry-Struktur einen eigenen Namen.
*
*--------------------------------------------------------------------*

	lea	MemName,a0			; Name der Node holen

	move.l	a0,LN_NAME(a1)			; Name in MemEntry eintragen

	move.l	ThisTask(a6),a0			; Aktuellen Task holen

	lea	TC_MEMENTRY(a0),a0		; MemList suchen

	CALL	AddTail				; MemEntry anhängen

	move.l	(sp)+,a1			; MemEntry holen
	move.l	ML_SIZE+ME_ADDR(a1),a1		; Speicherbereich merken

	lea	__H1_org,a0			; Anfang des Datensegments merken

	move.l	#((__H1_end-__H1_org)/4)-1,d0	; Länge des Datensegments merken

*--------------------------------------------------------------------*
*
*	Hier werden die Daten aus dem Programm in das erzeugte
*	Datensegment kopiert.
*
*--------------------------------------------------------------------*

1$	move.l	(a0)+,(a1)+			; Daten kopieren
	dbra	d0,1$

*--------------------------------------------------------------------*
*
*	Hier werden die letzten Vorkehrungen zum Starten des
*	Hautprogrammes getrofen.
*
*--------------------------------------------------------------------*

start	bsr	_geta4				; Basisregister laden
	move.l	a3,__savsp			; Alten Stackpointer setzen

	lea	DosName,a1			; Name der dos.library
	moveq	#0,d0				; Versionsnummer egal
	CALL	OpenLibrary			; Library öffnen
	move.l	d0,_DOSBase			; Erfolgreich?
	bne	2$				; Hauptprogramm aufrufen

	move.l	#AG_OpenLib!AO_DOSLib,d7	; Sense!
	lea	ThisTask(a6),a5			; Aktueller Task
	CALL	Alert				; Guru rufen
	bra	Error2				; Beenden

2$	move.l	a6,_SysBase			; SysBase setzen

	andi.w	#AFF_68881,AttnFlags(a6)	; FPU vorhanden
	beq	3$

	lea	Restore,a5
	CALL	Supervisor			; FPU zurücksetzen

3$	jsr	__main				; Hauptroutine aufrufen
	addq.l	#8,sp				; Stack korrigieren

*--------------------------------------------------------------------*
*
*	An dieser Stelle wird die dos.library geschlossen. Die
*	_exit() Routine täte dies, ist in diesem Fall aber nicht
*	aufgerufen worden.
*
*--------------------------------------------------------------------*

	move.l	_DOSBase,a1
	move.l	a1,d0				; dos.library noch offen?
	beq	4$				; Wohl nicht.

	move.l	AbsExecBase,a6			; SysBase
	CALL	CloseLibrary			; Library schließen

4$	rts					; Und zurück...

*--------------------------------------------------------------------*

Error2:	addq.l	#8,sp				; Stack korrigieren

	move.l	AbsExecBase,a6			; SysBase

*--------------------------------------------------------------------*
*
*	Für den Fall, daß dieses Programm von der Workbench
*	gestartet wurde, wird hier die Startup-Message abgefangen
*	und zurückgeschickt (nein, was arbeiten wir sauber!).
*
*--------------------------------------------------------------------*

	move.l	ThisTask(a6),a0			; Aktuellen Task holen
	tst.l	pr_CLI(a0)			; Von Workbench gestartet?
	bne	Error1

	lea	pr_MsgPort(a0),a0		; MsgPort merken
	move.l	a0,a3				; Zwischenspeichern

	CALL	WaitPort			; Auf WBenchStartup warten

	move.l	a3,a0				; MsgPort zurückladen

	CALL	GetMsg				; WBenchMsg abholen

	move.l	d0,a3				; Message zwischenspeichern

	CALL	Forbid				; Multitasking aus

	move.l	a3,a1				; Message zurückladen

	CALL	ReplyMsg			; Und zurückschicken

Error1:	moveq	#-1,d0				; Vermasselt!
	rts

*--------------------------------------------------------------------*
*
*	Diese Unterroutine wird zum Zurücksetzen einer möglicherweise
*	vorhandenen FPU verwendet.
*
*--------------------------------------------------------------------*

Restore:
	clr.l	-(sp)
	frestore (sp)+				; FPU zurücksetzen
	rte

*--------------------------------------------------------------------*
*
*	Eine der vielleicht wichtigsten Routinen des gesamten
*	Programmes. Sie setzt das globale Datenadressierungregister
*	a4 auf einen definierten Wert. Dieser Wert entspricht der
*	Anfangsadresse des Datensegments plus 32766.
*
*--------------------------------------------------------------------*

_geta4:
	movem.l	d0-d1/a0-a1/a6,-(sp)		; Alle Register retten,
						; verändert werden
	move.l	AbsExecBase,a6			; SysBase
	move.l	ThisTask(a6),a0			; Aktuellen Task finden
	lea	TC_MEMENTRY(a0),a0		; MemList merken
	lea	MemName,a1			; Name des MemEntry's merken

	CALL	FindName			; Listeneintrag suchen

	move.l	d0,a1
	move.l	ML_SIZE+ME_ADDR(a1),a4		; Anfang des Speicherbereichs
						; merken
	lea	32766(a4),a4			; Offset addieren

	movem.l	(sp)+,d0-d1/a0-a1/a6		; Alle Register zurückladen
	rts

*--------------------------------------------------------------------*

	endve.l	(sp)+,a1			