;---------------------------------------------------------------------
;Programm-/Routinen-Name:	Line-F Emulation Driver / LFED
;						 Version 1.00
;Datum: 15.02.92

;Aufgabe/Kurzdoku: Line-F-Emulator fr die Benutzung eines MC68881
;in einem Atari ST/STE mit MC68000 (also auch der SFP004-Karte).
;Mit LFED ist die Nutzung der FPU in vollem Umfang gew„hrleistet und
;kann von jedem Programm angesprochen werden, welches FPU-Untersttzung
;verlangt. MC68030 (TT) optimierte Programme sind hiervon natrlich
;ausgenommen, da der MC68000 dessen InstructionSet nicht versteht!

;Wird ein MC68882 als FPU genutzt, mssen einige kleinere Anpassungen
;vorgenommen werden, da dieser an verschiedenen Stellen šbertragungen
;des PC's erwartet.

;Author: Roger Butenuth (c't 04/90 Seite 430 ff.)
;		 Michael Hauschild (XBRA-Erweiterungen und alle folgenden
;		 Versionen)  

;	(c)	Smart Systems '92
;		Windhornstraže 2 / 3016 Seelze 1
;		Telefon (05137) 9 20 09

;Dokumentation: 

;Der Treiber installiert sich unter Beachtung des XBRA-Protokolls, 
;d.h. er erkennt sein Vorhandensein und gibt eine Meldung aus, falls
;versucht wird, ihn erneut zu installieren.

;Nicht untersttzte FPU-Befehle:

;	FTRAP, FSAVE, FRESTORE

;Erkannte BUGS in Version 1.00:

;	FMOVE (An),FP0-FPn  ... dieser ist eigentlich kein BUG !

;	Es tritt ein BUS-Error beim Terminieren von Programmen auf, die
;	die FPU nutzen und fr das Terminieren die C-Funktion return() 
;	verwenden. Der Grund hierfr ist ein Restore der FPU-Register
;	mit FMOVEM (diese werden am Programmbegin gesichert). Man kann
;	dieses SAUBER umgehen, indem man aus FPU-nutzenden Funktionen
;	mit exit() zurckkehrt - dann sollte auch kein Bus-Error mehr
;	auftreten (siehe FPU_TST2.C oder auch BGIDEMO.C)

;ACHTUNG: bei den Assembler-Options muž -S Flag gesetzt werden 
;(wegen ReTurn from Exception / RTE) ! 

;Letzte Žnderung:
;	19.05.92	Freigabe der Version 1.00, da der BUG mit FMOVE und
;				return(0) gefixt ist!

;---------------------------------------------------------------------
;-------------- macro - definitions ----------------------------------

.MACRO Supexec
	move.w		#38,-(sp)		;Supexec()
	trap		#14				;XBIOS
	addq.l		#6,sp			;Stack aufr„umen
.ENDM			
		
;-------------- set FPU-register-addresses ---------------------------
	
response 	equ 	$fffa40	;in a6 (Coprozessor-Basisregister)
control		equ		$02		;Alle weiteren Register relativ zu
save		equ		$04		;response
restore		equ		$06		
command		equ		$0a		;in a5
condition	equ		$0e
operand		equ		$10		;in a4
reg_selec	equ		$14
ins_add		equ		$18
lineF		equ		$2c		;Line-F / TRAP-No. 11

;-------------- start of code ----------------------------------------

			.TEXT
			pea.l		Install			;Installations-Routine
			Supexec						;SVC
			cmp.l		#"LFED",d1		;ist "LFED" ?
			beq			Terminate		;ja -> dann terminieren
			
start:		pea.l		titel			;Titel-Daten holen
			move.w		#9,-(sp)		;Cconws 
			trap		#1				;GEMDOS-Call
			addq.l		#6,sp			;Stack-Korrektur
	
			pea			setvec			;Im Supervisormodus Vektor setzen
			Supexec						;SVC
						
			movea.l		4(sp),a0		;Basepageadresse holen
			move.l		#$100,d1		;Basepagel„nge
			add.l		$0c(a0),d1		;+Textl„nge
			add.l		$14(a0),d1		;+Datenl„nge
			add.l		$1c(a0),d1		;+BSS-L„nge
			move.l		d1,-(sp)		;L„nge des belegten Speichers
			move.w		#$31,-(sp)		;an GEMDOS melden
			trap		#1
			
setvec:		move.l		lineF,oldtrap	;Alten Line-F-Vektor retten
			move.l		#newtrap,lineF	;Neuen Line-F-Vektor setzen
			rts
			
xb_magic:	.dc.b		"XBRA"			;XBRA-Struktur vor neuem Trap
xb_id:		.dc.b		"LFED"			;XBRA-Kennung

oldtrap:	.dc.l		0				;Platz fr alten Line-F-Vektor

;-------------- lineF-handler -----------------------------------------

newtrap:	move.l		d1,rd1			;D1 retten (nur fr eigenen Trap)
			move.l		2(sp),d1		;PC nach D1
			cmp.l		#$fc0000,d1		;PC-ROM-Anfang
			blt.s		my_trap			;PC<ROM-Anfang -> kam aus dem RAM
			movea.l		oldtrap,a0		;Adresse der alten Trap-Routine
			jmp			(a0)			;Alte Routine anspringen

my_trap:	move.l		rd1,d1			;D1 zurckholen
			movem.l		d0-a6,dregs		;Register retten
			move.l		usp,a0			;USP retten
			move.l		a0,rusp			;ber Umweg
			lea			response,a6		;#response nach A6
			lea			command(a6),a5	;#command  nach A5
			lea			operand(a6),a4	;#operand  nach A4
			lea			dregs,a3		;#dregs    nach A3
			movea.l		2(sp),a0		;PC nach A0
			move.w		(a0),d1			;Kommando nach D1
again:				;-------- Einsprung fr weitere FPU-Befehle
			and.w		#%0000000111000000,d1	;Spezialteil ausmaskieren
			bne			spezial			;Ein Bit gesetzt->Spezialbefehl
			move.w		2(a0),d1		;zweiten Befehlsteil in D1 merken
			move.w		d1,(a5)			;Befehl in FPU schreiben (A3==#command)
do_ca:				;-------- Einsprung fr weiter Nachfragen an FPU
			move.w		(a6),d0			;Response lesen
			btst		#12,d0			;erstes Modusbit testen
			bne			rw_1x			;==1 -> springen
			btst		#11,d0			;zweites Modusbit testen
			beq.s		rw_00			;==0 -> springen
			;-------- %xxx01, Null-Primitive/Transfer Single CPU-Register
			btst		#10,d0			;Register bertragen?
			bne.s		rw_sngl			;JA -> Transfer Single CPU-Register
			btst		#15,d0			;CA (Come Again) gesetzt?
			bne.s		do_ca			;JA -> weiter fragen, sonst fertig
			addq.l		#4,a0			;A0 um reine Befehlsl„nge weiter
					;(Alles andere wurde in calc_add erledigt)
			move.w		(a0),d1			;erstes Befehlswort holen
			move.w		d1,d0			;und nach D0
			and.w		#$f000,d0		;wieder COP-Befehl?
			eor.w		#$f000,d0
			beq.s		again			;JA -> direkt weiter machen
			move.l		a0,2(sp)		;neuen PC eintragen
			movea.l		rusp,a0			;USP wieder restaurieren
			move.l		a0,usp			;wieder ber Umweg
			movem.l		(a3),d0-a6		;Register restaurieren
			rte							;Trap beenden

rw_sngl:	and.w		#%1110000,d1	;Registernummer ausmaskieren (nur Dn)
			lsr.w		#2,d1			;D1=Nummer*4
			move.l		(a3,d1.w),(a4)	;Register bertragen (a4==#operand,a3==#dregs)
			bra.s		do_ca			;danach kommt immer noch etwas
			
rw_00:		;-------- %xxx00, Transfer multiple coprocessor registers
			bsr 		calc_add		;Operandenadresse nach A1 holen
			move.w		reg_selec(a6),d4	;Registerliste nach D4 holen
			btst		#13,d0			;Dr-Bit testen
			beq.s		w_00			;==0 -> Daten in FPU schreiben
						
			btst		#12,d0			;Predekrementmodus?
			beq.s		r_pred			;==0 -> ja, springen
			
			moveq		#7,d0			;Schleifenz„hler fr 8 Bits
			
.l_1:		lsl.w		#1,d4			;ein Bit ins Carry
			bcc.s		.l_2 			;nur bei Bit==1 etwas machen
			move.l		(a4),(a1)+		;1 (A4==#operand)
			move.l		(a4),(a1)+		;2
			move.l		(a4),(a1)+		;3 Langworte fr jedes Register
.l_2:		dbra		d0,.l_1			;fr alle 8 Bits

			bra			do_ca			;nochmal FPU befragen
			
r_pred:		moveq		#7,d0			;Schleifenz„hler fr 8 Bits

.l_1:		lsl.w		#1,d4			;ein Bit ins Carry
			bcc.s		.l_2			;nur bei Bit==1 etwas machen
			move.l		(a4),(a1)+		;1 (A4==#operand)
			move.l		(a4),(a1)+		;2
			move.l		(a4),(a1)+		;3 Langworte fr jedes Register
			suba.w		#24,a1			;Dekrement durchfhren
.l_2:		dbra		d0,.l_1			;fr alle 8 Bits

			adda.w		#12,a1			;A1 wieder auf letztes Register
			move.l		a1,(a2)			;A1 als Registerinhalt abspeichern

			bra			do_ca			;Nochmal FPU fragen
			
w_00:		move.w		(a0),d0			;erstes Befehlswort holen
			and.b		%111000,d0		;Adressierungsart maskieren
			cmp.b		%011000,d0		;Gleich (An)+ ?
			beq.s		w_post			;JA -> Postinkrementmodus

			moveq		#7,d0			;Schleifenz„hler fr 8 Bits

.l_1:		lsl.w		#1,d4			;ein Bit ins Carry
			bcc.s		.l_2			;nur bei Bit==1 etwas machen
			move.l		(a1)+,(a4)		;1 (A4==#operand)
			move.l		(a1)+,(a4)		;2
			move.l		(a1)+,(a4)		;3 Langworte fr jedes Register
.l_2:		dbra		d0,.l_1			;fr alle 8 Bits

			bra			do_ca			;Nochmal FPU fragen
			
w_post:		suba.w		#12,a1			;Inkrement von calc_add aufheben

			moveq		#7,d0			;Schleifenz„hler fr 8 Bits

.l_1:		lsl.w		#1,d4			;ein Bit ins Carry
			bcc.s		.l_2			;nur bei Bit==1 etwas machen
			move.l		(a1)+,(a4)		;1 (A4==#operand)
			move.l		(a1)+,(a4)		;2
			move.l		(a1)+,(a4)		;3 Langworte fr jedes Register
.l_2:		dbra		d0,.l_1			;fr alle 8 Bits
			move.l		a1,(a2)			;A1 als Registerinhalt abspeichern
			
			bra			do_ca			;Nochmal FPU fragen
			
rw_1x:		btst		#11,d0			;zweites Modusbit testen
			bne.s		rw_11			;==1 -> springen (Trap, Error)
			btst		#13,d0			;DR-Bit testen
			beq.s		w_10			;==0 -> Daten an FPU schreiben
			;--------  %xx110, evaluate effective address and transfer data
			bsr			calc_add		;Operandenadresse berechnen
										;A1=Operandenadresse, d1.l=Operandenl„nge
			cmp.w		#2,d1			;L„nge-2
			ble.s		r_bw			;<=2 -> Wort- oder Byteoperand
			
r_11:		move.l		(a4),(a1)+		;ein Langwort lesen (a4==#operand)
			subq.l		#4,d1			;und runterz„hlen
			bgt.s		r_11			;>0 -> weiter bertragen
			bra			do_ca			;Nochmal FPU befragen
			
r_bw:		btst		#0,d1			;Byte?
			bne.s		r_byte			;JA!
			move.w		(a4),(a1)		;Word-Operand lesen (A4==#operand)
			bra			do_ca			;Nochmal FPU befragen
			
r_byte:		move.b		(a4),(a1)		;Byteoperand lesen (A4==#operand)
			bra			do_ca			;Nochmal FPU befragen
			
w_10:		;--------  %xx010, evaluate effective address and transfer data
			bsr			calc_add		;Operandenadresse berechnen
										;A1=Operandenadresse, d1.l=Operandenl„nge
			cmp.w		#2,d1			;L„nge-2
			ble.s		w_bw			;<=2 -> Wort- oder Byteoperan
			
w_11:		move.l		(a1)+,(a4)		;Langwort schreiben (a4==#operand)
			subq.l		#4,d1			;und runterz„hlen
			bgt.s		w_11			;>0 -> weiter bertragen
			bra			do_ca			;Nochmal FPU befragen
			
w_bw:		btst		#0,d1			;Byte?
			bne.s		w_byte			;JA!
			move.w		(a1),(a4)		;Word schreiben (A4==#operand)
			bra			do_ca			;Nochmal FPU befragen
			
w_byte:		move.b		(a1),(a4)		;Byte schreiben (A4==#operand)
			bra			do_ca			;Nochmal FPU befragen
			
rw_11:		;-------- %xxx11, take pre-instruction exception
			bra 		cop_error		;Error-Handler anspringen
			;(hier sollte man eine genauere Fehleranalyse machen)!
			
spezial:				;Sprungbefehle etc.
			cmp.w		#%001000000,d1	;FScc, FDBcc oder FTRAPcc
			beq.s		s_trap
			cmp.w		#%010000000,d1	;Branch mit 16Bit-Offset
			beq			s_br16
			eor.w		#%011000000,d1	;Branch mit 32Bit-Offset
			beq			s_br32
			bra			cop_error		;FSAVE/FRESTORE nicht untersttzt
			
s_trap:		move.w		(a0),d0			;erstes Befehlswort nach D0
			move.w		d0,d1			;und nach D1 retten
			and.w		#%111000,d0		;wichtige Bits ausmaskieren
			cmp.w		#%001000,d0		;FDBcc?
			beq.s		s_fdbcc			;JA -> springen
			cmp.w		#%111000,d0		;FTRAP?
			beq			cop_error		;JA -> Fehler (s.o.)
										;sonst FScc
			move.w		2(a0),condition(a6)	;Bedingung an FPU schicken
			moveq		#1,d0			;Operandenl„nge=1 (fr calc_add)
			bsr			calc_add		;Operandenl„nge berechnen
			
.l_1:		move.w		(a6),d0			;Response lesen
			btst		#8,d0			;IA-Bit testen
			beq.s		.l_2			;==0 -> fertig
			and.w		#%1100000000000,d0	;Bit 11 und 12 ausmaskieren
			eor.w		#%1100000000000,d0	;Beide gesetzt?
			bne.s		.l_1			;nicht Beide ==1 -> warten
			bra			cop_error		;sonst Exception aufgetreten
			
.l_2:		btst		#0,d0			;Antwortbit testen
			sne			(a1)			;je nach Bit setzen/l”schen
			bra			do_ca			;nochmal FPU befragen
			
s_fdbcc:	move.w		2(a0),condition(a6)	;Bedingung an FPU schicken
			and.w		#%111,d1		;Registernummer maskieren (D1=(A0))
			lsl.w		#2,d1			;D1=Nummer*4
			lea			(a3,d1.w),a1	;A1 enth„lt Adresse des Datenregisters
			move.l		(a1),d1			;Dn holen
			subq.w		#1,d1			;Dn=Dn-1
			move.l		d1,(a1)			;Dn zurckschreiben
			movea.l		a0,a2			;alten PC nach A2 holen
			addq.l		#2,a0			;PC 2 weiter (fr "nicht springen")
						
.l_1:		move.w		(a6),d0			;Response lesen
			btst		#8,d0			;IA-Bit testen
			beq.s		.l_2			;==0 -> fertig
			and.w		#%1100000000000,d0	;Bit 11 und 12 ausmaskieren
			eor.w		#%1100000000000,d0	;Beide gesetzt?
			bne.s		.l_1			;nicht Beide ==1 -> warten
			bra			cop_error		;sonst Exception aufgetreten
			
.l_2:		btst		#0,d0			;Antwortbit testen
			bne			do_ca			;TRUE -> das war's schon
			adda.w		4(a2),a2		;16Bit Sprungdist. add. (A2=PC)
			addq.w		#1,d1			;Dn==1 ?
			beq			do_ca			;JA -> kein Sprung (Schleifenende)
			movea.l		a2,a0			;sonst "Sprung" (neuen PC laden)
			bra			do_ca			;nochmal FPU befragen
			
s_br16:		move.w		(a0),condition(a6)	;Bedingung an FPU schicken

.l_1:		move.w		(a6),d0			;Response lesen
			btst		#8,d0			;IA-Bit testen
			beq.s		.l_2			;==0 -> fertig
			and.w		#%1100000000000,d0	;Bit 11 und 12 ausmaskieren
			eor.w		#%1100000000000,d0	;Beide gesetzt?
			bne.s		.l_1			;nicht Beide ==1 -> warten
			bra			cop_error		;sonst Exception aufgetreten
			
.l_2:		btst		#0,d0			;Antwortbit testen
			beq			do_ca			;FALSE -> das war's schon
			adda.w		2(a0),a0		;16Bit Sprungdistanz addieren
			subq.l		#2,a0			;ein Wort zurck (weil sp„ter
			;noch addiert wird und nur 2 addiert werden mžte)
			bra			do_ca			;nochmal FPU befragen
			
s_br32:		move.w		(a0),condition(a6)	;Bedingung an FPU schicken

.l_1:		move.w		(a6),d0			;Response lesen
			btst		#8,d0			;IA-Bit testen
			beq.s		.l_2			;==0 -> fertig
			and.w		#%1100000000000,d0	;Bit 11 und 12 ausmaskieren
			eor.w		#%1100000000000,d0	;Beide gesetzt?
			bne.s		.l_1			;nicht Beide ==1 -> warten
			bra			cop_error		;sonst Exception aufgetreten
			addq.l		#2,a0			;Befehl ist 3 Worte lang
										;(nun: (A0)=Distanz)			
.l_2:		btst		#0,d0			;Antwortbit testen
			beq			do_ca			;TRUE -> das war's schon
			adda.l		(a0),a0			;32Bit Sprungdistanz addieren
			subq.l		#4,a0			;ein Wort zurck (weil sp„ter
			;noch addiert wird und nur 2 addiert werden mžte)
			bra			do_ca			;nochmal FPU befragen
			
cop_error:		;Error_Handler fr einen TRAP der FPU (sehr einfach gehalten).
				;Es wird ein Reset der FPU durchgefhrt und das aktuelle
				;Programm terminiert. Return-Code = 881.
			move.w		#0,control(a6)	;FPU-Reset (kein clr.w verwenden!)
			move.w		#881,-(sp)		;Return-Code
			move.w		#$4c,-(sp)		;Funktion Pterm(881)
			trap		#1				;des GEMDOS aufrufen
			
calc_add:
	;Operandenadresse berechnen. A0 muž die Adresse des Line-F-Befehls 
	;enthalten, D0 im unteren Byte die Operandenl„nge. Die zu berechnende
	;Adresse wird in A1 abgelegt. A0 wird um die L„nge der zus„tzlichen
	;Daten erh”ht. Zus„tzlichen wird in D1 die L„nge des Operanden zurck-
	;gegeben (in Bytes, als Langwort). D2, D3, A2 werden zerst”rt. Bei den
	;Adressierungsarten -(An), (An)+ steht in A2 ein Zeiger auf die Stelle,
	;in der der Inhalt des Adressregisters An steht (wird fr FMOVEM 
	;gebraucht).
	
			clr.l		d1				;L„nge als Langwort l”schen
			move.b		d0,d1			;und Byte einkopieren
			move.w		(a0),d2			;Erstes Befehlswort nach D2
			move.w		d2,d3			;und nach D3 retten
			and.w		#%111000,d3		;Adressierungsart ausmaskieren
			lsr.w		#1,d3			;D3=Adressierungsart*4 (Langworte!)
			lea			cs_tab,a1		;Sprungtabellenadresse nach A1
			move.l		(a1,d3.w),a1	;Adresse der Routine nach A1
			jmp			(a1)			;und Routine anspringen
			
c_drd:		;%000	Data Register Direct:		Dn
c_ard:		;%001	Address Register Direct:	An
			lea			(a3),a1			;A1 auf Registerfeld
			and.w		#%1111,d2		;Registernummer ausmaskieren
			;(und ein Bit vom Modus, 0 fr Daten-, 1 fr Adressregister)
			lsl.w		#2,d2			;D2="Registernummer"*4 (+Modusbit!)
			addq.w		#4,d2			;+4 (fr Operandenl„nge)
			sub.w		d1,d2			;wahre L„nge abziehen
			adda.w		d2,a1			;Offset auf Registerfeldanfang add.
			rts
			
c_ari:		;%010	Address Register Indirect:	(An)
			and.w		#%111,d2		;Registernummer ausmaskieren
			lsl.w		#2,d2			;D2="Registernummer"*4 
			move.l		32(a3,d2.w),a1	;Adresse nach A1
			rts
			
c_arpo:		;%011	ARI with Postincrement:		(An)+
			and.w		#%111,d2		;Registernummer ausmaskieren
			lsl.w		#2,d2			;D2="Registernummer"*4 
			lea 		32(a3,d2.w),a2	;Adresse Adressregister nach A2
			movea.l		(a2),a1			;Adresse (Inhalt A.-Reg.) nach A1
			btst		#0,d1			;D1 ungerade? (Byteoperand)
			bne.s		.l_2			;JA -> Spezialbehandlung
			
.l_1:		add.l		d1,(a2)			;Inkrement durchfhren
			rts
			
.l_2:		cmp.w		#4*7,d2			;ist A7 gemeint?
			bne.s		.l_1			;NEIN -> normal vorgehen
			addq.l		#2,(a2)			;sonst (bei Byte) 2 addieren,
			rts							;damit Stack gerade bleibt!
			
c_arpr:		;%100	ARI with Predecrement:		-(An)
			and.w		#%111,d2		;Registernummer ausmaskieren
			lsl.w		#2,d2			;D2="Registernummer"*4 
			lea 		32(a3,d2.w),a2	;Adresse Adressregister nach A2
			btst		#0,d1			;D1 ungerade? (Byteoperand)
			bne.s		.l_2			;JA -> Spezialbehandlung
			
.l_1:		sub.l		d1,(a2)			;Inkrement durchfhren
			movea.l		(a2),a1			;Adresse (Inhalt des A.-Reg.) nach A1
			rts
			
.l_2:		cmp.w		#4*7,d2			;ist A7 gemeint?
			bne.s		.l_1			;NEIN -> normal vorgehen
			subq.l		#2,(a2)			;sonst (bei Byte) 2 subtrahieren,
			   							;damit Stack gerade bleibt!
			movea.l		(a2),a1			;Adresse (Inhalt A.-Reg.) nach A1
			rts
			
c_ar16:		;%101	ARI with Displacement:		d16(An)
			and.w		#%111,d2		;Registernummer ausmaskieren
			lsl.w		#2,d2			;D2="Registernummer"*4 
			movea.l		32(a3,d2.w),a1	;Adresse nach A1
			move.w		4(a0),d2		;3. Befehlswort nach D2 (Offset)
			adda.w		d2,a1			;Offset auf Adresse addieren
			addq.l		#2,a0			;A0 ein Wort (d16) weiter
			rts
			
c_ar08:		;%110	ARI with Index:				d8(An,Xn)
			and.w		#%111,d2		;Registernummer ausmaskieren
			lsl.w		#2,d2			;D2="Registernummer"*4 
			movea.l		32(a3,d2.w),a1	;Adresse nach A1
			move.w		4(a0),d2		;3. Befehlswort nach D2 (Offset)
			move.w		d2,d3			;und nach D3
			and.w		#$ff,d3			;Byte ausmaskieren (Byte-Offset)
			adda.w		d3,a1			;Offset auf Adresse addieren
			btst		#11,d2			;1=long, 0=word
			bne.s		c_ar81
			and.w		#%1111000000000000,d2	;Nummer von Dn und Modusbit
			lsr.w		#5,d2					;maskieren
			lsr.w		#5,d2			;D2=Registernummer*4 (+Modusbit)
			adda.w		2(a3,d2.w),a1	;16Bit-Index auf A1 addieren
			addq.l		#2,a0			;A0 ein Wort (Kram & d8) weiter
			rts
			
c_ar81:		and.w		#%1111000000000000,d2	;Nummer von Dn und Modusbit
			lsr.w		#5,d2					;maskieren
			lsr.w		#5,d2			;D2=Registernummer*4 (+Modusbit)
			adda.l		(a3,d2.w),a1	;32Bit-Index auf A1 addieren
			addq.l		#2,a0			;A0 ein Wort (Kram & d8) weiter
			rts
			
c_pc:		;%111	absolut short/long, PC-Relativ (ohne/mit Index)
			;oder direkt
			btst		#2,d2			;Immidiate?
			bne.s		immi			;!=0 -> JA
			btst		#1,d2			;PC-Relativ?
			bne.s		pc_rel			;!=0 -> JA
			btst		#0,d2			;Long?
			bne.s		c_long			;!=0 -> JA
										;sonst Short
			move.w		4(a0),d2		;Wortadresse holen,
			ext.l		d2				;Auf Langwort erweitern
			movea.l		d2,a1			;und als Operandenadresse merken
			addq.l		#2,a0			;A0 ein Wort (Short-Addr.) weiter
			rts

c_long:		movea.l		4(a0),a1		;Langwortadresse holen
			addq.l		#4,a0			;A0 zwei Worte (Long-Addr.) weiter
			rts
			
immi:		movea.l		a0,a1   		;Langwortadresse holen
			addq.l		#4,a1			;Beide Befehlsworte berspringen
			adda.l		d1,a0			;A0 ber Operand hinwegsetzen
			rts
			
pc_rel:		btst		#0,d2			;mit Index?
			bne.s		pc_idx			;!=0 -> JA
			movea.l		a0,a1			;PC nach A1
			adda.w		4(a0),a1		;Offset addieren
			addq.l		#4,a1			;+4 fr L„nge des FPU-Befehls
			addq.l		#2,a0			;A0 zwei (16Bit-Offset) weiter
			rts
			
pc_idx:		move.l		a0,a1			;PC nach A1
			clr.w		d2				;oberes Byte l”schen
			move.b		5(a0),d2		;Offset nach D2
			adda.w		d2,a1			;und addieren
			addq.l		#4,a1			;+4 fr L„nge des FPU-Befehls
			move.b		4(a0),d2			;D2=Registernummer*16 und Modusbit
										;(high-byte ist noch 0)
			btst		#3,d2			;Long-Bit testen
			bne.s		pc_i_l			;!=0 -> Long-Index
			and.w		#%111110000,d2	;Restinformation ausblenden
			lsr.w		#2,d2			;D2=Registernummer*4 und Modusbit
			adda.w		2(a3,d2.w),a1	;Word-Index addieren
			addq.l		#2,a0			;A0 zwei (16Bit-Offset) weiter
			rts
			
pc_i_l:		and.w		#%111110000,d2	;Restinformation ausblenden
			lsr.w		#2,d2			;D2=Registernummer*4 und Modusbit
			adda.l		(a3,d2.w),a1	;Long-Index addieren
			addq.l		#2,a0			;A0 zwei (16Bit-Offset) weiter
			rts			;ENDE von calc_add ***

;-------------- installation-handler ---------------------------------

Install:	movea.l		lineF,a0 		;Vektor nach A0
        	move.l		(-12.b,a0),d0	;falls "XBRA" -> jetzt in D0
			move.l		(-8.b,a0),d1	;falls "LFED" -> jetzt in D1
			rts 
			
Terminate:	pea			failure			;Fehlermeldung
			move.w		#9,-(sp)		;Cconws
			trap		#1				;GEMDOS
			move.w		#0,-(sp)		;richtig terminieren
			trap		#1				;mit Pterm(0)/GEMDOS
						
;-------------- data-segment -----------------------------------------
			
			.DATA
			
cs_tab:		.dc.l	c_drd,c_ard,c_ari,c_arpo	;Sprungtabelle fr
			.dc.l	c_arpr,c_ar16,c_ar08,c_pc	;Adressierungsarten

titel:      .dc.b 	10, 13, 27, 112	;CR/invers on
			.ASCII	"  Line-F-Emulation-Driver LFED  ", 10, 13 
            .ASCII	"        Version 1.00            ", 10, 13
			.dc.b	27, 113         ;invers off
			.ASCII  "   (c) by Smart Systems '92", 10, 13
			.ASCII  " Michael Hauschild / Seelze", 10, 13
			.ASCII  " Phone: 05137 / 9 20 09", 10, 13, 0

failure:	.dc.b	10, 13	;CR
			.ASCIIZ	" LFED already installed"
			.dc.b	10, 13	;CR
			
;-------------- blockstorage-segment ---------------------------------
			
			.BSS

dregs:		.ds.l	(8+7)	;Platz fr Register (D0-D7/A0-A6)
rusp:		.ds.l	1		;Platz fr USP (A7)
rd1:		.ds.l	1		;Platz fr D1

;-------------- end of code ------------------------------------------

			.END