aboutsummaryrefslogtreecommitdiffstats
path: root/tests/t_parsys
diff options
context:
space:
mode:
Diffstat (limited to 'tests/t_parsys')
-rw-r--r--tests/t_parsys/asflags1
-rw-r--r--tests/t_parsys/float.i681226
-rw-r--r--tests/t_parsys/float81.i68293
-rw-r--r--tests/t_parsys/parsys.i68115
-rw-r--r--tests/t_parsys/t_parsys.asm994
-rw-r--r--tests/t_parsys/t_parsys.doc8
-rw-r--r--tests/t_parsys/t_parsys.inc10
-rw-r--r--tests/t_parsys/t_parsys.oribin0 -> 7516 bytes
8 files changed, 2647 insertions, 0 deletions
diff --git a/tests/t_parsys/asflags b/tests/t_parsys/asflags
new file mode 100644
index 0000000..01f6552
--- /dev/null
+++ b/tests/t_parsys/asflags
@@ -0,0 +1 @@
+-c \ No newline at end of file
diff --git a/tests/t_parsys/float.i68 b/tests/t_parsys/float.i68
new file mode 100644
index 0000000..fbfc1e9
--- /dev/null
+++ b/tests/t_parsys/float.i68
@@ -0,0 +1,1226 @@
+; FLOAT.I68
+;-----------------------------------------------------------------------------
+; Fliesskommaroutinen fuer den PC-PAR 68000, Version ohne 68881
+; entnommen mc 11/88, c't...
+
+;-----------------------------------------------------------------------------
+; Definitionen
+
+vorz equ 0
+subflag equ 1
+maxexpo equ 255
+bias equ 127
+extend equ $10
+e equ $402df854 ; exp(1)
+ln2 equ $3f317218 ; ln(2)
+ln10 equ $40135d8e ; ln(10)
+eins equ $3f800000 ; 1.0
+zwei equ $40000000 ; 2.0
+pi2 equ $40c90fdb ; Pi*2
+pi equ $40490fdb ; Pi
+pihalf equ $3fc90fdb ; Pi/2
+
+;-----------------------------------------------------------------------------
+; Librarykopf:
+
+
+S_FloatLib: dc.l S_floatlibend-S_floatlibstart ; Laenge
+S_floatlibstart:
+ dc.l -1 ; Speicher fuer Zeiger
+ dc.b "FLOAT",0 ; Name
+ ds 0
+
+
+
+;-----------------------------------------------------------------------------
+; Sprungtabelle:
+
+ bra.l S_fadd
+ bra.l S_fsub
+ bra.l S_fmul
+ bra.l S_fdiv
+ bra.l S_fmul2
+ bra.l S_fsqrt
+ bra.l S_fabs
+ bra.l S_floatlibnop
+ bra.l S_fcmp
+ bra.l S_fitof
+ bra.l S_fftoi
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_fexp
+ bra.l S_fsinh
+ bra.l S_fcosh
+ bra.l S_ftanh
+ bra.l S_fcoth
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_fln
+ bra.l S_flog
+ bra.l S_fasinh
+ bra.l S_facosh
+ bra.l S_fatanh
+ bra.l S_facoth
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_fsin
+ bra.l S_fcos
+ bra.l S_ftan
+ bra.l S_fcot
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_floatlibnop
+ bra.l S_fasin
+ bra.l S_facos
+ bra.l S_fatan
+ bra.l S_facot
+
+
+;-----------------------------------------------------------------------------
+; Konstanten :
+
+S_Const1 dc.s 1.0
+
+;-----------------------------------------------------------------------------
+; Nullprozedur :
+
+S_floatlibnop: rts
+
+;-----------------------------------------------------------------------------
+; Addition : D0.S = D0.S + D1.S
+
+ ds 0
+S_fadd:
+ addq.l #1,_fadd_cnt.w
+ movem.l d1-d5,-(a7) ; benoetigte Register retten
+ rol.l #1,d0 ; Operanden rotieren und in Form
+ rol.l #1,d1 ; eeee eeee ffff ... fffs bringen
+ move.l d0,d2
+ sub.l d1,d2 ; Differenz beider Zahlen bilden
+ bcc.s fadd_1
+ exg d0,d1 ; ggf. vertauschen, so dass der
+fadd_1: move.b d0,d3 ; kleinere in Register D1 steht
+ and.b #1,d3 ; maskiere das Vorzeichenbit
+ btst #vorz,d2 ; haben beide gleiches Vorzeichen ?
+ beq.s fadd_2 ; bei verschiedenen Vorzeichen
+ bset #subflag,d3 ; Flag fuer Subtraktion setzen
+fadd_2: rol.l #8,d0 ; Form: ffff ... fffs eeee eeee
+ clr.w d4 ; Exponent der ersten Zahl
+ move.b d0,d4 ; wird im Register D4 aufgebaut
+ sne d0 ; falls ungleich Null, dann
+ ror.l #1,d0 ; implizite Eins, sonst implizite
+ clr.b d0 ; Null erzeugen, neu positionieren
+
+ rol.l #8,d1 ; jetzt das gleiche fuer den
+ clr.w d5 ; zweiten Operanden, der Exponent
+ move.b d1,d5 ; kommt ins Register D5
+ sne d1
+ ror.l #1,d1
+ clr.b d1
+
+; In den Registern D0 und D1 stehen jetzt nur noch die Mantissen
+; im Format ffff ... ffff 0000 0000, also linksbuendig, wobei die
+; ehemals implizite Null bzw. Eins nun explizit an erster Stelle steht.
+; In den Registern D4 und D5 stehen die Exponenten der beiden Zahlen.
+; Das Vorzeichen des Ergebnisses sowie die Subtraktionsflags sind im
+; Register D3 zwischengespeichert.
+
+ move.w d4,d2 ; Jetzt Differenz der Exponenten
+ sub.w d5,d2 ; berechnen
+ cmp.w #24,d2 ; groesser als 24 ?
+ bgt.s fadd_rnd ; ja, --> Ergebnis ist groessere Zahl
+ lsr.l d2,d1 ; Mantisse um (D2)-Bits verschieben
+ btst #subflag,d3 ; Subtraktion oder Addition ?
+ bne.s fadd_subtr ; ggf. zur Subtraktion springen
+ add.l d1,d0 ; die beiden Mantissen addieren
+ bcc.s fadd_rnd ; kein Ueberlauf --> zum Runden
+ roxr.l #1,d0 ; Ueberlauf einschieben
+ addq.w #1,d4 ; Exponent korrigieren
+ bra.s fadd_rnd ; und zum Runden
+
+fadd_subtr: sub.l d1,d0 ; die beiden Mantissen subtrahieren
+ beq.s fadd_zero ; bei Null ist das Gesamtergebnis Null
+ bmi.s fadd_rnd ; bei fuehrender Eins zum Runden
+fadd_nrm: tst.w d4 ; Exponent ist schon Null ?
+ beq.s fadd_rnd ; dann ist Ergebnis denormalisiert
+ subq.w #1,d4 ; Exponent erniedrigen
+ lsl.l #1,d0 ; Mantisse normalisieren bis
+ bpl.s fadd_nrm ; fuehrende Eins auftaucht
+
+fadd_rnd: add.l #$80,d0 ; jetzt Runden auf Bit hinter
+ bcc.s fadd_nov ; Mantisse
+ roxr.l #1,d0 ; bei Ueberlauf Mantisse normalisieren
+ addq.w #1,d4 ; und Exponent korrigieren
+fadd_nov: clr.b d0 ; Rest-Mantisse loeschen
+ tst.l d0 ; Ist die Mantisse komplett Null ?
+ beq.s fadd_zero ; ja, dann ist Ergebnis auch Null
+ cmp.w #maxexpo,d4 ; Exponent-Ueberlauf ?
+ blt.s fadd_nue
+ move.w #maxexpo,d4 ; Unendlich Exponent = maxexpo
+ clr.l d0 ; Mantisse = Null
+ bra.s fadd_den
+
+fadd_nue: tst.w d4 ; Exponent Null ( Zahl denormalisiert? )
+ beq.s fadd_den ; ja -->
+ lsl.l #1,d0 ; fuehrendes Bit wird nicht gespeichert
+fadd_den: move.b d4,d0 ; Exponent einsetzen
+ ror.l #8,d0 ; Form: eeee eeee ffff ... fffx
+ roxr.b #1,d3 ; Vorzeichen in Carry schieben
+ roxr.l #1,d0 ; Form: seee eeee efff ... ffff
+
+fadd_zero:
+ movem.l (a7)+,d1-d5 ; Register restaurieren
+ rts ; Ende, Ergebnis steht in D0.L
+
+;-----------------------------------------------------------------------------
+; Subtraktion : D0.S = D0.S - D1.S
+
+ ds 0
+S_fsub:
+ bchg #31,d1 ; Vorzeichen des zweiten Operanden
+ bra S_fadd ; invertieren und zur Addition springen
+
+
+;-----------------------------------------------------------------------------
+; Multiplikation : D0.S = D0.S * D1.S
+
+ ds 0
+S_fmul:
+ addq.l #1,_fmul_cnt.w
+ movem.l d1-d5,-(a7) ; benoetigte Register retten
+ move.l d0,d2 ; Operand 1 kopieren
+ eor.l d1,d2 ; EXOR um Vorzeichen zu bestimmen
+
+ swap d0 ; Registerhaelften Operand 1 vertauschen
+ move.l d0,d3 ; Operand 1 ab jetzt in Register D3
+ and.w #$7f,d3 ; Exponent und Vorzeichen loeschen
+ and.w #$7f80,d0 ; Exponent maskieren
+ beq.s fmul_dn1 ; gleich Null: Zahl ist denormalisiert
+ bset #7,d3 ; implizite Eins einsetzen
+ sub.w #$0080,d0 ; Bias kompensieren
+
+fmul_dn1: swap d1 ; jetzt Operand 2 behandeln
+ move.w d1,d4
+ and.w #$7f,d1
+ and.w #$7f80,d4
+ beq.s fmul_dn2
+ bset #7,d1
+ sub.w #$0080,d4 ; Bias kompensieren
+
+fmul_dn2: add.w d0,d4 ; Exponenten addieren
+ lsr.w #7,d4 ; richtig positionieren
+ sub.w #bias-3,d4 ; Bias-3 subtrahieren
+ cmp.w #-24,d4 ; totaler Unterlauf ?
+ blt.s fmul_zero ; ja, dann ist Ergebnis Null
+
+ move.w d3,d0 ; oberes Mantissenwort von Operand 1
+ mulu d1,d0 ; mal oberem Mantissenwort von Op2
+ swap d0 ; entspricht Verschiebung um 16 Bit
+
+; Das obere Wort von D0 ist nach der Multiplikation auf jeden Fall Null,
+; da die oberen Mantissenworte nur im Bereich 0 ... 255 liegen.
+; Das groete moegliche Ergebnis ist also 255 x 255 = 65025 = 0000FE01.
+; Nach der Vertauschung erhalten wir also eine Zahl der xxxx 0000.
+; Die untere Registerhaelfte von D0 koennen wir kurzzeitig als Zwischen-
+; speicher verwenden.
+
+ move.w d3,d0 ; oberes Wort von Operand 1 merken
+ swap d3 ; jetzt unteres Wort Op1 mal oberes Op2
+ move.w d1,d5
+ mulu d3,d5 ; Ergebnis steht im D5
+ swap d1 ; jetzt unteres Wort Op1 mal unteres Op2
+ mulu d1,d3 ; Ergebnis steht im D3
+ swap d3 ; entspricht Verschiebung um 16 Bit
+ mulu d0,d1 ; jetzt oberes Wort Op1 mal unteres Op2
+
+ move.w d3,d0 ; zum ersten Zwischenergebnis dazu
+ add.l d5,d0 ; jetzt alles aufaddieren
+ add.l d1,d0
+ beq.s fmul_res ; falls Mantisse Null auch Ergebnis Null
+ bmi.s fmul_rnd ; fuehrende Eins? dann zum Runden
+
+; Im Register D0.L befinden sich die oberen 32 Bit des Produktes,
+; im oberen Wort von D3 die restlichen 16 Bit.
+
+ tst.w d4 ; Exponent ist negativ ?
+ bmi.s fmul_unt ; ggf. Unterlauf behandeln
+
+fmul_nor: tst.w d4 ; Exponent = Null ?
+ beq.s fmul_rnd ; falls Null, dann zum Runden
+ roxl.l #1,d3 ; Im oberen Wort von D3 sind die
+ roxl.l #1,d0 ; niedrigsten Bits des Produktes
+ subq.w #1,d4 ; Exponent korrigieren
+ tst.l d0 ; Mantisse testen
+ bpl.s fmul_nor ; bis fuehrende Eins auftaucht
+
+fmul_rnd: add.l #$80,d0 ; Rundung
+ bcc.s fmul_nov
+ roxr.l #1,d0 ; Ueberlauf einschieben
+ addq.w #1,d4 ; Exponent korrigieren
+fmul_nov: cmp.w #maxexpo,d4 ; Exponent-Ueberlauf ?
+ blt.s fmul_nue
+fdiv_err: move.w #maxexpo,d4 ; Ueberlauf: Exponent = Maxexpo
+ clr.l d0 ; Mantisse = Null
+ bra.s fmul_den
+
+fmul_nue: tst.w d4 ; Exponent = Null ?
+ beq.s fmul_den ; falls Null, dann denormalisiert
+ lsl.l #1,d0 ; fuehrende Eins wird nicht abgespeichert
+
+fmul_den: move.b d4,d0 ; Exponent einsetzen
+ ror.l #8,d0 ; Form: eeee eeee ffff ... fffx
+ roxl.l #1,d2 ; Vorzeichen in Carry schieben
+ roxr.l #1,d0 ; und ins Ergebnis einsetzen
+
+fmul_res: movem.l (a7)+,d1-d5 ; Register restaurieren
+ rts
+
+fmul_zero: clr.l d0 ; Null erzeugen
+ bra.s fmul_res ; Ende, Ergebnis steht in D0.L
+
+fmul_unt: cmp.w #-24,d4 ; totaler Unterlauf ?
+ ble.s fmul_zero ; Dann ist das Ergebnis auf jeden Fall Null
+ neg.w d4 ; sonst Shift-Zaehler erzeugen
+ lsr.l d4,d0 ; und Zahl denormalisieren
+ clr.w d4 ; Exponent ist Null als Kennzeichen
+ bra.s fmul_rnd ; fuer eine denormalisierte Zahl
+
+;-----------------------------------------------------------------------------
+; Division : D0.S = D0.S / D1.S
+
+ ds 0
+S_fdiv:
+ addq.l #1,_fdiv_cnt.w
+ movem.l d1-d5,-(a7) ; benoetigte Register retten
+ move.l d0,d2 ; Operand 1 kopieren
+ eor.l d1,d2 ; EXOR um Vorzeichen zu bestimmen
+
+ swap d0 ; Registerhaelften Operand 1 vertauschen
+ move.l d0,d3 ; Operand 1 ab jetzt in Register D3
+ and.w #$7f,d3 ; Exponent und Vorzeichen loeschen
+ and.w #$7f80,d0 ; Exponent maskieren
+ beq.s fdiv_dn1 ; gleich Null: Zahl ist denormalisiert
+ bset #7,d3 ; implizite Eins einsetzen
+ sub.w #$0080,d0 ; Bias kompensieren
+
+fdiv_dn1: swap d1 ; jetzt Operand 2 behandeln
+ move.w d1,d4
+ and.w #$7f,d1
+ and.w #$7f80,d4
+ beq.s fdiv_dn2
+ bset #7,d1
+ sub.w #$0080,d4
+
+fdiv_dn2: sub.w d4,d0 ; Exponenten subtrahieren
+ move.w d0,d4 ; Exponent nach D4 kopieren
+ asr.w #7,d4 ; richtig positionieren
+ add.w #bias,d4 ; Bias addieren
+ cmp.w #-24,d4 ; totaler Ueberlauf ?
+ blt.s fmul_zero ; ja, dann ist Ergebnis Null
+
+ swap d1 ; Form: 0fff ... ffff 0000 0000
+ beq.s fdiv_err ; falls Divisor Null, dann wird
+ lsl.l #7,d1 ; als Ergebnis unendlich ausgegeben
+ swap d3
+ beq.s fmul_zero ; falls Divident Null --> Ergebnis Null
+ lsl.l #7,d3
+
+fdiv_nlp: btst #30,d1 ; ist der Divisor normalisiert ?
+ bne.s fdiv_nor ; ja, -->
+ addq.w #1,d4 ; nein, Exponent erhoehen
+ lsl.l #1,d1 ; Divisor verschieben bis Form 01ff ..
+ bra.s fdiv_nlp
+
+fdiv_nor: clr.l d0 ; Ergebnis vorbesetzen
+ add.w #25,d4 ; Exponent ist nicht groesser als Null
+
+fdiv_lop: move.l d3,d5 ; Divident zwischenspeichern
+ sub.l d1,d3 ; Divisor abziehen
+ eori #extend,ccr ; X-Bit invertieren
+ bcc.s fdiv_one ; kein Carry: Divisor passt
+ move.l d5,d3 ; zurueckkopieren (X-Bit unveraendert!)
+fdiv_one: roxl.l #1,d0 ; Ergebnis aufbauen
+ lsl.l #1,d3 ; Divident verschieben
+ subq.w #1,d4 ; Exponent erniedrigen
+ beq.s fdiv_den ; falls Null, dann denormalisiert
+ btst #24,d0 ; fuehrende Eins in Ergebnis-Mantisse?
+ beq.s fdiv_lop ; nein, weiter rechnen
+
+fdiv_den: lsl.l #7,d0 ; Mantisse positionieren
+ beq fmul_res ; Null ?
+ bra fmul_rnd ; zum Runden
+;-----------------------------------------------------------------------------
+; Multiplikation mit einer Zweierpotenz: D0.S=D0.S * 2^(D1.W)
+
+ ds 0
+S_fmul2:
+ addq.l #1,_fmul_cnt.w
+ movem.l d1-d2,-(a7) ; Register retten
+ move.l d0,d2 ; Vorzeichen in D2 Bit 31 merken
+ lsl.l #1,d0 ; Vorzeichen rausschieben
+ beq.s fmul2_zero ; falls Null, dann ist Ergebnis Null
+ rol.l #8,d0 ; Form: ffff ... fff0 eeee eeee
+ clr.w d2 ; auf Wort vorbereiten
+ move.b d0,d2 ; Exponent in D2
+ beq.s fmul2_den
+ tst.w d1 ; Multiplikation oder Division?
+ bmi.s fmul2_div ; (neg. Exponent entspr. Div.)
+
+ add.w d1,d2 ; Summe der Exponenten bilden
+ cmp.w #maxexpo,d2 ; Ueberlauf?
+ bge.s fmul2_over ; ja, Ergebnis ist unendlich
+fmul2_res: move.b d2,d0 ; Ergebnisexponent einsetzen
+ ror.l #8,d0 ; Form: eeee eeee ffff ... fffx
+ roxl.l #1,d2 ; Vorzeichen ins X-Bit
+ roxr.l #1,d0 ; und ins Ergebnis einschieben
+fmul2_zero: movem.l (a7)+,d1-d2 ; Register restaurieren
+ rts
+
+fmul2_over: move.w #maxexpo,d2 ; Unendlich: Exponent = maxexpo
+ clr.l d0 ; Mantisse = Null
+ bra.s fmul2_res
+
+fmul2_div: add.w d1,d2 ; Summe der Exponenten bilden
+ bgt.s fmul2_res ; Unterlauf? nein --> Ergebnis
+ ori #Extend,ccr ; implizite Eins real machen
+ roxr.l #1,d0 ; Form: 1fff ... ffff xxxx xxxx
+fmul2_dnr: tst.w d2 ; Exponent = Null ?
+ beq.s fmul2_res ; ja, Ergebnis ist denormalisiert
+ lsr.l #1,d0 ; Mantisse denormalisieren
+ beq.s fmul2_zero ; totaler Unterlauf: Ergebnis ist Null
+ addq.w #1,d2 ; Exponent korrigieren
+ bra.s fmul2_dnr
+fmul2_ddd: add.w d1,d2 ; Summe der Exponenten bilden
+ bra.s fmul2_dnr ; mit denormalisiereter Eingabe bearbeiten
+
+fmul2_den: tst.w d1 ; Multiplikation oder Division
+ bmi.s fmul2_ddd
+ clr.b d0 ; Form: ffff ... fff0 0000 0000
+fmul2_nor: lsl.l #1,d0 ; Mantisse nach links schieben
+ bcs.s fmul2_stp ; bis fuehrende Eins auftaucht
+ subq.w #1,d1 ; oder zweiter Exponent Null wird
+ bne.s fmul2_nor
+ bra.s fmul2_res ; Ergebnis abliefern
+fmul2_stp: add.w d1,d2 ; Rest zum Exponenten addieren
+ bra.s fmul2_res ; Bias stimmt auch ( jetzt 127 statt 126)
+
+;-----------------------------------------------------------------------------
+; Vergleich zweier Zahlen: cmp d0,d1
+
+S_fcmp:
+ bclr #31,d0 ; Zahl 1 >=0 ?
+ bne.s fcmp_2
+fcmp_1:
+ bclr #31,d1 ; Zahl 2 >=0 ?
+ bne.s fcmp_12
+fcmp_11:
+ cmp.l d1,d0 ; beide Zahlen >=0
+ rts ; dann Betraege vergleichen
+fcmp_12:
+ moveq.l #1,d0 ; Zahl 1 >=0 und Zahl 2 <0
+ cmp.l #-1,d0
+ rts
+fcmp_2:
+ bclr #31,d1 ; Zahl 2 >=0 ?
+ bne.s fcmp_22
+fcmp_21:
+ moveq.l #-1,d0 ; Zahl 1 <0 und Zahl 2 >=0
+ cmp.w #1,d0 ; dann kleiner
+ rts
+fcmp_22:
+ neg.l d0
+ neg.l d1
+ cmp.l d1,d0 ; beide Zahlen <0, dann ver-
+ rts ; kehrtherum vergleichen
+
+
+;-----------------------------------------------------------------------------
+; Longint-->Gleitkomma
+; D0.L --> D0.S
+
+S_fitof:
+ movem.l d1-d2,-(a7) ; Register retten
+ tst.l d0 ; Integer ist Null ?
+ beq.s fitof_res; Ergebnis ist auch Null
+ smi d1 ; Vorzeichen in D1 merken
+ bpl.s fitof_pos
+ neg.l d0 ; ggf. Integer negieren
+fitof_pos: move.w #bias+32,d2 ; Exponent vorbesetzen
+fitof_shift: subq.w #1,d2 ; Mantisse verschieben
+ lsl.l #1,d0 ; bis fuehrende Eins rausfliegt
+ bcc.s fitof_shift
+ move.b d2,d0 ; Exponent einsetzen
+ ror.l #8,d0 ; Zahl positionieren
+ roxr.b #1,d1 ; Vorzeichen in X-Bit
+ roxr.l #1,d0 ; und ins Ergebnis
+fitof_res: movem.l (a7)+,d1-d2 ; fertig
+ rts
+
+;-----------------------------------------------------------------------------
+; Gleitkomma --> Longint:
+; D0.S --> D0.L
+
+S_fftoi:
+ movem.l d1-d2,-(a7) ; Register retten
+ roxl.l #1,d0 ; Vorzeichen in Carry
+ scs d1 ; in D1 merken
+ rol.l #8,d0 ; Form: ffff ... fffx eeee eeee
+ move.b d0,d2 ; Exponent extrahieren
+ sub.b #bias,d2 ; Bias subtrahieren
+ bmi.s fftoi_zero ; kleiner Null -> Ergebnis = Null
+ cmp.b #31,d2 ; Ueberlauf?
+ bge.s fftoi_over
+ ori #extend,ccr ; Implizite Eins explizit machen
+ roxr.l #1,d0
+ clr.b d0 ; Form: 1fff ... ffff 0000 0000
+fftoi_shft:
+ lsr.l #1,d0 ; jetzt Verschiebung bis
+ addq.b #1,d2 ; Exponent stimmt
+ cmp.b #31,d2
+ bne.s fftoi_shft
+ tst.b d1 ; Zahl negativ ?
+ bpl.s fftoi_pos
+ neg.l d0 ; ggf. Ergebnis negieren
+fftoi_pos:
+ movem.l (a7)+,d1-d2 ; Register wieder holen
+ rts
+fftoi_zero:
+ clr.l d0 ; Unterlauf; Ergebnis ist Null
+ bra.s fftoi_pos
+fftoi_over:
+ move.l #$7fffffff,d0 ; Ueberlauf: Maxint zurueckgeben
+ tst.b d1 ; positiv oder negativ ?
+ bpl.s fftoi_pos
+ not.l d0 ; Einser-Komplement erzeugt Minint
+ bra.s fftoi_pos
+
+;-----------------------------------------------------------------------------
+; Quadratwurzel : D0.S-->D0.S
+
+ ds 0
+fsqrt_domainerror:
+ move.l #$ffc00000,d0 ; -NAN zurueckgeben
+ movem.l (a7)+,d1-d4
+ rts
+fsqrt_sq0:
+ clr.l d0
+ movem.l (a7)+,d1-d4
+ rts
+S_fsqrt:
+ addq.l #1,_fsqrt_cnt.w
+ movem.l d1-d4,-(a7) ; D1-D4 werden sonst zerstoert
+ move.l d0,d4
+ bmi.s fsqrt_domainerror ; Fehler bei negativem Argument
+ swap d4 ; MSW des Arguments
+ and.l #$7f80,d4 ; Exponent isolieren
+ beq.s fsqrt_sq0 ; Zahl ist 0, wenn Exponent 0
+ and.l #$007fffff,d0 ; Mantisse isolieren
+ sub.w #$7f*$80,d4 ; Exponent im Zweierkomplement
+ bclr #7,d4 ; Exponent ungerade? (und LSB auf 0)
+ beq.s fsqrt_evenexp
+ add.l d0,d0 ; ja: Mantisse * 2
+ add.l #$01000000-$00800000,d0 ; Hidden Bit setzen, 1.Iteration
+
+fsqrt_evenexp:
+ ; 1. Iteration fuer geraden Exponenten: Hidden Bit nicht setzen
+ asr.w #1,d4 ; Exponent/2 mit Vorzeichen
+ add.w #$7f*$80,d4 ; Exponent wieder in Offset-Darst.
+ swap d4 ; neuen Exponenten im MSW aufheben
+ lsl.l #7,d0 ; x ausrichten
+ move.l #$40000000,d2 ; xroot nach erster Iteration
+ move.l #$10000000,d3 ; m2=2 << (MaxBit-1);
+fsqrt_loop10:
+ move.l d0,d1 ; xx2 = x
+fsqrt_loop11:
+ sub.l d2,d1 ; xx2 -= root
+ lsr.l #1,d2 ; xroot >>= 1
+ sub.l d3,d1 ; x2 -= m2
+ bmi.s fsqrt_dontset1
+ move.l d1,d0 ; x = xx2
+ or.l d3,d2 ; xroot += m2
+ lsr.l #2,d3 ; m2 >>= 2
+ bne.s fsqrt_loop11
+ bra.s fsqrt_d0d1same
+fsqrt_dontset1:
+ lsr.l #2,d3 ; m2 >>= 2
+ bne.s fsqrt_loop10 ; Schleife 15* abarbeiten
+ ; Bit 22..8
+ ; 17. Iteration (Bit 7) mit separatem Code durchfuehren:
+ move.l d0,d1 ; xx2 = x
+fsqrt_d0d1same:
+ sub.l d2,d1 ; xx2 -= root
+ ror.l #1,d2 ; xroot >>= 1 mitsamt Carry...
+ swap d2 ; auf neues Alignment umstellen
+ subq.l #1,d1 ; Carry von 0-0x4000: x2 -= m2
+ ; Teil 1
+ bmi.s fsqrt_dontset7
+ or.l #-$40000000,d1 ; 0 - 0x4000: x2 -= m2, Teil 2
+ move.l d1,d0 ; x = xx2
+ or.w #$4000,d2 ; xroot += m2
+fsqrt_dontset7:
+ swap d0 ; x auf neues Alignment umstellen
+
+ move.w #$1000,d3 ; m2 - Bit 16..31 bereits 0
+fsqrt_loop20:
+ move.l d0,d1 ; xx2 = x
+fsqrt_loop21:
+ sub.l d2,d1 ; xx2 -= xroot
+ lsr.l #1,d2 ; xroot >>= 1
+ sub.l d3,d1 ; x2 -= m2
+ bmi.s fsqrt_dontset2
+ move.l d1,d0 ; x = xx2
+ or.w d3,d2 ; xroot += m2
+ lsr.w #2,d3 ; m2 >>= 2
+ bne.s fsqrt_loop21
+ bra.s fsqrt_finish
+fsqrt_dontset2:
+ lsr.w #2,d3 ; m2 >>= 2
+ bne.s fsqrt_loop20 ; Schleife 7 * abarbeiten (n=6..0)
+fsqrt_finish:
+ sub.l d2,d0 ; Aufrunden notwendig ?
+ bls.s fsqrt_noinc
+ addq.l #1,d2 ; wenn ja, durchfuehren
+fsqrt_noinc:
+ bclr #23,d2 ; Hidden Bit loeschen
+ or.l d4,d2 ; Exponent und Mantisse kombinieren
+ move.l d2,d0 ; Ergebnis
+ movem.l (a7)+,d1-d4
+ rts ; Z-,S-, und V-Flag o.k.
+
+;-----------------------------------------------------------------------------
+; Absolutbetrag: D0.S--> D0.S
+
+ ds 0
+
+S_fabs: bclr #31,d0 ; ganz einfach...
+ rts
+
+;-----------------------------------------------------------------------------
+; Exponentialfunktion: D0.S--> D0.S
+
+; Die "krummen" Konstanten legen wir als hex ab, damit es keine Vergleichs-
+; fehler durch Rundungsvarianzen gibt.
+
+S_fexp_Const0: dc.l $3FB8AA3B ; ld(exp(1.0)) = ld(e) = 1/ln(2)
+S_fexp_ConstA: dc.l $3D0DF4E0 ; 0.034657359038 Polynomkonstanten
+S_fexp_ConstB: dc.l $411F4606 ; 9.9545957821
+S_fexp_ConstC: dc.l $441A7E3A ; 617.97226953
+S_fexp_ConstD: dc.l $42AED5C2 ; 87.417498202
+
+ ds 0
+S_fexp: movem.l d1-d5,-(sp)
+
+ bclr #31,d0 ; Vorzeichen loeschen und nach D2 retten
+ sne d2
+
+ move.l S_fexp_Const0(pc),d1 ; auf 2erpotenz umrechnen
+ bsr S_fmul
+
+ move.l d0,d3 ; in Ganzzahlanteil und Nach-
+ bsr S_fftoi ; kommastellen (z) zerlegen
+ move.l d0,d4 ; Ganzzahlanteil nach D4
+ bsr S_fitof
+ move.l d0,d1
+ move.l d3,d0
+ bsr S_fsub
+ move.l d0,d3
+
+ move.l d0,d1 ; z^2 berechnen
+ bsr S_fmul
+ move.l d0,d5 ; noch zu gebrauchen
+
+ move.l S_fexp_ConstD(pc),d1 ; --> D+z^2
+ bsr S_fadd
+ move.l d0,d1 ; --> C/(..)
+ move.l S_fexp_ConstC(pc),d0
+ bsr S_fdiv
+ move.l d0,d1 ; --> B-(..)
+ move.l S_fexp_ConstB(pc),d0
+ bsr S_fsub
+ move.l d3,d1 ; --> (..)-z
+ bsr S_fsub
+ exg d0,d5 ; Ergebnis retten
+ move.l S_fexp_ConstA(pc),d1 ; A*z^2 berechnen
+ bsr S_fmul
+ move.l d5,d1 ; ergibt Nenner
+ bsr S_fadd
+ move.l d0,d1 ; Quotient bilden
+ move.l d3,d0
+ bsr S_fdiv
+ moveq #1,d1 ; verdoppeln
+ bsr S_fmul2
+ move.l S_Const1(pc),d1 ; 1 addieren
+ bsr S_fadd
+ move.l d4,d1 ; Potenzieren
+ bsr S_fmul2
+
+ tst.b d2 ; war Argument negativ ?
+ beq.s S_fexp_ArgPos
+ move.l d0,d1 ; dann Kehrwert bilden
+ move.l S_Const1(pc),d0
+ bsr S_fdiv
+
+Terminate:
+S_fexp_ArgPos: movem.l (sp)+,d1-d5
+
+ rts
+
+;------------------------------------------------------------------------------
+; Sinus hyperbolicus: D0.S-->D0.S
+
+S_fsinh:
+ movem.l d1-d2,-(a7) ; Register retten
+ bsr S_fexp ; exp(x) berechnen
+ move.l d0,d2 ; in D2 merken
+ move.l d0,d1 ; exp(-x)=1/exp(x) berechnen
+ move.l #eins,d0
+ bsr S_fdiv
+ move.l d0,d1 ; Teilergebnisse subtrahieren
+ move.l d2,d0
+ bsr S_fsub
+ move.w #-1,d1 ; halbieren
+ bsr S_fmul2
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+
+;------------------------------------------------------------------------------
+; Cosinus hyperbolicus: D0.S-->D0.S
+
+S_fcosh:
+ movem.l d1-d2,-(a7) ; Register retten
+ bsr S_fexp ; exp(x) berechnen
+ move.l d0,d2 ; in D2 merken
+ move.l d0,d1 ; exp(-x)=1/exp(x) berechnen
+ move.l #eins,d0
+ bsr S_fdiv
+ move.l d2,d1 ; Teilergebnisse addieren
+ bsr S_fadd
+ move.w #-1,d1 ; halbieren
+ bsr S_fmul2
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Tangens hyperbolicus: D0.S-->D0.S
+
+S_ftanh:
+ movem.l d1-d3,-(a7) ; Register sichern
+ bsr S_fexp ; exp(x) berechnen
+ move.l d0,d2 ; in D2 merken
+ move.l d0,d1 ; exp(-x)=1/exp(x) berechnen
+ move.l #eins,d0
+ bsr S_fdiv
+ move.l d0,d3 ; in D3 merken
+ move.l d2,d1 ; Summe=Nenner berechnen
+ bsr S_fadd
+ exg d0,d2 ; jetzt exp(x) in D0, Nenner
+ move.l d3,d1 ; in D2
+ bsr S_fsub ; Zaehler berechnen
+ move.l d2,d1 ; Quotient berechnen
+ bsr S_fdiv
+ movem.l (a7)+,d1-d3 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Cotangens hyperbolicus: D0.S-->D0.S
+
+S_fcoth:
+ tst.l d0 ; Argument Null ?
+ beq.s S_fcoth_valerr ; dann zur Fehlerroutine
+ movem.l d1-d3,-(a7) ; Register sichern
+ bsr S_fexp ; exp(x) berechnen
+ move.l d0,d2 ; in D2 merken
+ move.l d0,d1 ; exp(-x)=1/exp(x) berechnen
+ move.l #eins,d0
+ bsr S_fdiv
+ move.l d0,d3 ; in D3 merken
+ move.l d0,d1 ; Differenz=Nenner berechnen
+ move.l d2,d0
+ bsr S_fsub
+ exg d0,d2 ; jetzt exp(x) in D0, Nenner
+ move.l d3,d1 ; in D2
+ bsr S_fadd ; Zaehler berechnen
+ move.l d2,d1 ; Quotient berechnen
+ bsr S_fdiv
+ movem.l (a7)+,d1-d3 ; Register zurueck
+ rts
+S_fcoth_valerr:
+ move.l #$7f800000,d0 ; +INF zurueckgeben
+ rts
+
+;-----------------------------------------------------------------------------
+; nat. Logarithmus: D0.S-->D0.S
+
+ ds 0
+S_fln:
+ tst.l d0 ; Argument <=0 ?
+ ble S_fln_errval
+ movem.l d1-d7,-(a7) ; Register retten
+ move.l d0,d3 ; Argument sichern
+
+ move.l #eins,d1 ; Zahl>1?
+ bsr S_fsub ; ( dies ist sinnvoll bei
+ tst.l d0 ; Zahlen <<1 );
+ smi d7 ; und die Vorzeichenumkehr merken
+ bpl.s S_fln_gr1 ; ja-->o.k.
+ move.l d3,d1 ; ansonsten Kehrwert bilden
+ move.l #eins,d0
+ bsr S_fdiv
+ move.l d0,d3
+
+S_fln_gr1:
+ clr.l d2 ; Merker = Null
+S_fln_nrm:
+ move.l d3,d0 ; Zahl > 1 ?
+ move.l #eins,d1
+ bsr S_fsub
+ bmi.s S_fln_isok
+ beq.s S_fln_isok
+ sub.l #$00800000,d3 ; ja-->Zahl durch 2 teilen...
+ addq.w #1,d2 ; ...und Merker erhoehen
+ bra.s S_fln_nrm ; nochmal probieren
+S_fln_isok:
+ move.l d0,d3 ; Zahl um Eins erniedrigt abspeichern
+ move.l d0,d4 ; yz:=y
+ moveq.l #1,d6 ; zaehler:=1
+ clr.l d5 ; Summe:=0
+ bchg #31,d3 ; Multiplikator negativ
+S_fln_loop:
+ move.l d6,d0 ; Zaehler in Gleitkomma wandeln
+ bsr S_fitof
+ move.l d0,d1 ; s:=s+yz/zaehler*vz
+ move.l d4,d0
+ bsr S_fdiv
+ move.l d5,d1
+ bsr S_fadd
+ cmp.l d5,d0 ; noch signifikant ?
+ beq.s S_fln_loopend
+ move.l d0,d5
+ addq.w #1,d6 ; zaehler:=zaehler+1
+ cmp.w #10,d6 ; Schleife fertig ?
+ beq.s S_fln_loopend
+ move.l d4,d0 ; yz:=yz*y
+ move.l d3,d1
+ bsr S_fmul
+ move.l d0,d4
+ bra.s S_fln_loop
+S_fln_loopend:
+ move.l d2,d0 ; Merker in Gleitkomma
+ bsr S_fitof
+ move.l #ln2,d1 ; * ln(2)
+ bsr S_fmul
+ move.l d5,d1 ; s:=s+merker
+ bsr S_fadd
+
+ tst.b d7 ; noch Vorzeichen tauschen ?
+ beq.s S_fln_end
+ bchg #31,d0
+S_fln_end:
+ movem.l (a7)+,d1-d7 ; Register zurueck
+ rts
+S_fln_errval:
+ move.l #$ffc00000,d0 ; -NAN zurueckgeben
+ rts
+
+;-----------------------------------------------------------------------------
+; 10er-Logarithmus : D0.S --> D0.S
+
+S_flog:
+ tst.l d0 ; Argument <=0 ?
+ ble.s S_flog_errval
+ bsr S_fln ; nat. Logarithmus bilden
+ move.l #ln10,d1 ; umrechnen
+ bsr S_fdiv
+ rts
+S_flog_errval:
+ move.l #$ffc00000,d0 ; -NAN zurueckgeben
+ rts
+
+;-----------------------------------------------------------------------------
+; Areasinus hyperbolicus: D0.S-->D0.S == ln[x+sqrt(x*x+1)]
+
+S_fasinh:
+ movem.l d1-d2,-(a7)
+ move.l d0,d2 ; Argument sichern
+ move.l d0,d1 ; quadrieren
+ bsr S_fmul
+ move.l #eins,d1 ; 1 addieren
+ bsr S_fadd
+ bsr S_fsqrt ; Wurzel ziehen
+ move.l d2,d1 ; Argument addieren
+ bsr S_fadd
+ bsr S_fln ; Logarithmus des ganzen
+ movem.l (a7)+,d1-d2
+ rts
+
+;-----------------------------------------------------------------------------
+; Areacosinus hyperbolicus: D0.S-->D0.S == ln[x+sqrt(x*x-1)]
+
+S_facosh:
+ movem.l d1-d2,-(a7) ; Register sichern
+ move.l d0,d2 ; Argument sichern
+ move.l #eins,d1 ; Argument <1 ?
+ bsr S_fcmp
+ bmi.s S_facosh_errval
+ move.l d2,d0 ; Argument zurueck
+ move.l d0,d1 ; quadrieren
+ bsr S_fmul
+ move.l #eins,d1 ; 1 abziehen
+ bsr S_fsub
+ bsr S_fsqrt ; Wurzel ziehen
+ move.l d2,d1 ; Argument addieren
+ bsr S_fadd
+ bsr S_fln ; Logarithmus des ganzen
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_facosh_errval:
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ move.l #$ffc00000,d0 ; NAN zurueckgeben
+ rts
+
+;-----------------------------------------------------------------------------
+; Areatangens hyperbolicus: D0.S-->D0.S == 0.5*ln((1+x)/(1-x))
+
+S_fatanh:
+ movem.l d1-d2,-(a7) ; Register sichern
+ move.l d0,d2 ; Argument sichern
+ bclr #31,d0 ; Vorzeichen weg
+ cmp.l #eins,d0
+ beq.s S_fatanh_inf ; =1-->INF
+ bhi.s S_fatanh_errval ; >1-->NAN
+ move.l d2,d1 ; Nenner berechnen
+ move.l #eins,d0
+ bsr S_fsub
+ exg d0,d2 ; Zaehler berechnen
+ move.l #eins,d1
+ bsr S_fadd
+ move.l d2,d1 ; Quotient daraus
+ bsr S_fdiv
+ bsr S_fln ; logarithmieren
+ move.w #-1,d1 ; halbieren
+ bsr S_fmul2
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_fatanh_inf:
+ move.l #$ff000000,d0 ; vorzeichenbehaftete Unend-
+ roxr.l #1,d0 ; lichkeit
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_fatanh_errval:
+ move.l #$7fc00000,d0 ; NAN geben
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Areakotangens hyperbolicus: D0.S--> D0.S == 0.5*ln((1+x)/(x-1))
+
+S_facoth:
+ movem.l d1-d2,-(a7) ; Register sichern
+ move.l d0,d2 ; Argument sichern
+ roxl.l #1,d0 ; Vorzeichen in X-Flag
+ cmp.l #eins*2,d0
+ beq.s S_facoth_inf ; =1-->INF
+ bmi.s S_facoth_errval ; <1-->NAN
+ move.l d2,d0 ; Nenner berechnen
+ move.l #eins,d1
+ bsr S_fsub
+ exg d0,d2 ; Zaehler berechnen
+ move.l #eins,d1
+ bsr S_fadd
+ move.l d2,d1 ; Quotient daraus
+ bsr S_fdiv
+ bsr S_fln ; logarithmieren
+ move.w #-1,d1 ; halbieren
+ bsr S_fmul2
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_facoth_inf:
+ move.l #$ff000000,d0 ; vorzeichenbehaftete Unend-
+ roxr.l #1,d0 ; lichkeit
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_facoth_errval:
+ move.l #$7fc00000,d0 ; NAN geben
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Kosinusfunktion: D0.S--> D0.S
+
+ ds 0
+S_fcos:
+ movem.l d1-d6,-(a7) ; Register retten
+ bclr #31,d0 ; cos(-x)=cos(x)
+
+ move.l #pi2,d1 ; auf Bereich 0..2*Pi reduzieren
+S_fcos_subtr:
+ cmp.l d1,d0 ; x>=2*Pi ?
+ blo.s S_fcos_subend ; ja-->Ende
+ bchg #31,d1 ; fuer Subtraktion
+ bsr S_fadd ; reduzieren
+ bchg #31,d1 ; Subtrahend wieder richtig
+ bra.s S_fcos_subtr
+S_fcos_subend:
+ cmp.l #pi,d0 ; x>Pi ?
+ blo.s S_fcos_nosub
+ exg d0,d1 ; ja-->cos(x)=cos(2*Pi-x)
+ bsr S_fsub
+S_fcos_nosub:
+ move.l d0,d1 ; wir brauchen nur x^2
+ bsr S_fmul
+ bset #31,d0
+ move.l d0,d3 ; -x^2 in D3
+ move.l d0,d4 ; D4 enthaelt laufende Potenz von x^2
+ ; inkl. Vorzeichen
+ move.l #zwei,d5 ; D5 enthaelt laufende Fakultaet
+ move.l #eins,d2 ; D2 enthaelt Summe
+ moveq.l #2,d6 ; D6 enthaelt Zaehler
+S_fcos_loop:
+ move.l d5,d1 ; s:=s+yz/zaehler
+ move.l d4,d0
+ bsr S_fdiv
+ move.l d2,d1
+ bsr S_fadd
+ cmp.l d2,d0 ; Veraendert sich Summe noch ?
+ beq.s S_fcos_end
+ move.l d0,d2
+ addq.b #2,d6 ; i:=i+1
+ cmp.b #22,d6 ; i=11 ?
+ beq.s S_fcos_end
+ move.w d6,d0 ; Fakultaet erhhen: *(2n-1)*(2n)
+ mulu.w d6,d0 ; =4*n^2-2*n
+ sub.w d6,d0
+ bsr S_fitof ; dazumultiplizieren
+ move.l d5,d1
+ bsr S_fmul
+ move.l d0,d5
+ move.l d4,d0 ; yz:=yz*y
+ move.l d3,d1
+ bsr S_fmul
+ move.l d0,d4
+ bra.s S_fcos_loop
+S_fcos_end:
+ ; Ergebnis bereits in D0
+ movem.l (a7)+,d1-d6 ; Register zurueck
+ rts
+
+;----------------------------------------------------------------------------
+; Sinus : D0.S-->D0.S
+
+S_fsin:
+ move.l d1,-(a7) ; Register retten
+ move.l #pihalf,d1 ; sin(x)=cos(x-pi/2)
+ bsr S_fsub
+ bsr S_fcos
+ move.l (a7)+,d1 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Tangens: D0.S-->D0.S
+
+S_ftan:
+ movem.l d1-d4,-(a7) ; Register retten
+ tst.l d0 ; Vorzeichen merken
+ smi d4
+ bclr #31,d0
+ move.l #pi,d1 ; auf Bereich 0..Pi reduzieren
+S_ftan_subtr:
+ cmp.l d1,d0 ; x>=Pi ?
+ blo.s S_ftan_subend ; ja-->Ende
+ bchg #31,d1 ; fuer Subtraktion
+ bsr S_fadd ; reduzieren
+ bchg #31,d1 ; Subtrahend wieder richtig
+ bra.s S_ftan_subtr
+S_ftan_subend:
+ move.l d0,d2 ; Argument merken
+ bsr S_fcos ; Nenner rechnen
+ move.l d0,d3 ; Nenner merken
+ move.l d0,d1 ; sqr(1-x^2) rechnen
+ bsr S_fmul
+ move.l d0,d1
+ move.l #eins,d0
+ bsr S_fsub
+ bsr S_fsqrt
+ move.l d3,d1
+ bsr S_fdiv ; Quotient
+ tst.b d4 ; Vorzeichen dazu
+ beq.s S_ftan_noneg
+ bchg #31,d0
+S_ftan_noneg:
+ movem.l (a7)+,d1-d4 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Kotangens: D0.S-->D0.S
+
+S_fcot:
+ movem.l d1-d4,-(a7) ; Register retten
+ tst.l d0 ; Vorzeichen merken
+ smi d4
+ bclr #31,d0
+ move.l #pi,d1 ; auf Bereich 0..Pi reduzieren
+S_fcot_subtr:
+ cmp.l d1,d0 ; x>=Pi ?
+ blo.s S_fcot_subend ; ja-->Ende
+ bchg #31,d1 ; fuer Subtraktion
+ bsr S_fadd ; reduzieren
+ bchg #31,d1 ; Subtrahend wieder richtig
+ bra.s S_fcot_subtr
+S_fcot_subend:
+ move.l d0,d2 ; Argument merken
+ bsr S_fcos ; Zaehler rechnen
+ move.l d0,d3 ; Zaehler merken
+ move.l d0,d1 ; sqr(1-x^2) rechnen
+ bsr S_fmul
+ move.l d0,d1
+ move.l #eins,d0
+ bsr S_fsub
+ bsr S_fsqrt
+ move.l d0,d1
+ move.l d3,d0
+ bsr S_fdiv ; Quotient
+ tst.b d4 ; Vorzeichen dazu
+ beq.s S_fcot_noneg
+ bchg #31,d0
+S_fcot_noneg:
+ movem.l (a7)+,d1-d4 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Arcustangens: D0.S-->D0.S
+
+S_fatan:
+ movem.l d1-d6,-(a7) ; Register sichern
+ subq.l #2,a7 ; Platz fuer Hilfsvariablen
+ tst.l d0 ; Vorzeichen merken...
+ smi (a7)
+ bclr #31,d0 ; ...und loeschen
+ cmp.l #eins,d0 ; Argument>1 ?
+ shi 1(a7) ; ja :
+ bls.s S_fatan_no1 ; nein :
+ move.l d0,d1 ; ja : Kehrwert bilden
+ move.l #eins,d0
+ bsr S_fdiv
+S_fatan_no1:
+ move.l #3,d2 ; Zaehler initialisieren
+ move.l d0,d5 ; Summe initialisieren
+ move.l d0,d4 ; laufende Potenz = x^1
+ move.l d0,d1 ; x^2 berechnen
+ bsr S_fmul
+ move.l d0,d3
+ bset #31,d3 ; immer mit -x^2 multiplizieren
+S_fatan_loop:
+ move.l d4,d0 ; naechste Potenz ausrechnen
+ move.l d3,d1
+ bsr S_fmul
+ move.l d0,d4
+ move.l d2,d0 ; Nenner in Gleitkomma
+ bsr S_fitof
+ move.l d0,d1 ; Division ausfuehren
+ move.l d4,d0
+ bsr S_fdiv
+ move.l d5,d1 ; zur Summe addieren
+ bsr S_fadd
+ cmp.l d0,d5 ; noch signifikant ?
+ beq.s S_fatan_endloop ; nein-->Ende
+ move.l d0,d5
+ addq.l #2,d2 ; Zaehler erhoehen
+ cmp.l #61,d2 ; fertig ?
+ bne.s S_fatan_loop
+S_fatan_endloop:
+ move.l d5,d0 ; Ergebnis in D0 bringen
+ tst.b 1(a7) ; war Argument < 1 ?
+ beq.s S_fatan_not2
+ bchg #31,d0 ; ja : Erg.=Pi/2-Erg
+ move.l #pihalf,d1
+ bsr S_fadd
+S_fatan_not2:
+ tst.b (a7) ; Vorzeichen dazu
+ beq.s S_fatan_not1
+ bset #31,d0
+S_fatan_not1:
+ addq.l #2,a7 ; Hilfsvar. abraeumen
+ movem.l (a7)+,d1-d6 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Arcuskotangens: D0.S-->D0.S
+
+S_facot:
+ move.l d1,-(a7) ; Register sichern
+ bsr S_fatan ; acot(x)=pi/2-atan(x)
+ bchg #31,d0
+ move.l #pihalf,d1
+ bsr S_fadd
+ move.l (a7)+,d1 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Arcussinus: D0.S --> D0.S
+
+S_fasin:
+ movem.l d1-d2,-(a7) ; Register retten
+ move.l d0,d2 ; Argument merken
+ move.l d0,d1 ; Quadrat berechnen
+ bsr S_fmul
+ bset #31,d0 ; 1-x^2 bilden
+ move.l #eins,d1
+ bsr S_fadd
+ tst.l d0 ; Sonderfaelle abfangen
+ bmi.s S_fasin_errval ; <0 geht nicht
+ beq.s S_fasin_inf ; Endwerte
+ bsr S_fsqrt ; Wurzel ...
+ move.l d0,d1 ; ... und Quotient
+ move.l d2,d0
+ bsr S_fdiv
+ bsr S_fatan ; zuletzt das wichtigste
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_fasin_errval:
+ move.l #$7fc00000,d0 ; NAN zurueckgeben
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_fasin_inf:
+ move.l #pihalf,d0 ; +- pi/2 zurueckgeben
+ and.l #$80000000,d2 ; Vorzeichen dazu
+ or.l d2,d0
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+
+;-----------------------------------------------------------------------------
+; Arcuskosinus: D0.S --> D0.S
+
+S_facos:
+ tst.l d0 ; Argument=0 ?
+ beq.s S_facos_inf
+ move.l d0,d2 ; Argument merken
+ move.l d0,d1 ; Quadrat berechnen
+ bsr S_fmul
+ bset #31,d0 ; 1-x^2 bilden
+ move.l #eins,d1
+ bsr S_fadd
+ tst.l d0 ; Sonderfaelle abfangen
+ bmi.s S_facos_errval ; <0 geht nicht
+ bsr S_fsqrt ; Wurzel ...
+ move.l d2,d1 ; ... und Quotient
+ bsr S_fdiv
+ bsr S_fatan ; zuletzt das wichtigste
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_facos_errval:
+ move.l #$7fc00000,d0 ; NAN zurueckgeben
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+S_facos_inf:
+ move.l #pihalf,d0 ; +- pi/2 zurueckgeben
+ and.l #$80000000,d2 ; Vorzeichen dazu
+ or.l d2,d0
+ movem.l (a7)+,d1-d2 ; Register zurueck
+ rts
+
+S_floatlibend:
diff --git a/tests/t_parsys/float81.i68 b/tests/t_parsys/float81.i68
new file mode 100644
index 0000000..ed5a3dc
--- /dev/null
+++ b/tests/t_parsys/float81.i68
@@ -0,0 +1,293 @@
+;----------------------------------------------------------------------------
+; Fliesskommaroutinen fuer den PcPar68000 - Version mit 68881
+
+;-----------------------------------------------------------------------------
+; Definitionen:
+
+CoConst1 equ $32 ; Offsets im Konstantenrom
+CoConstPi equ 0 ; des 6888x
+
+;-----------------------------------------------------------------------------
+; Librarykopf:
+
+
+S_Float81Lib: dc.l S_float81libend-S_float81libstart ; Laenge
+S_float81libstart:
+ dc.l -1 ; Speicher fuer Zeiger
+ dc.b "FLOAT",0 ; Name
+ ds 0
+
+
+;-----------------------------------------------------------------------------
+; Sprungtabelle:
+
+ bra.l S_fadd_co68
+ bra.l S_fsub_co68
+ bra.l S_fmul_co68
+ bra.l S_fdiv_co68
+ bra.l S_fsqrt_co68
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_fcmp_co68
+ bra.l S_fitof_co68
+ bra.l S_fftoi_co68
+ bra.l S_fabs_co68
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_fexp_co68
+ bra.l S_fsinh_co68
+ bra.l S_fcosh_co68
+ bra.l S_ftanh_co68
+ bra.l S_fcoth_co68
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_fln_co68
+ bra.l S_flog_co68
+ bra.l S_fasinh_co68
+ bra.l S_facosh_co68
+ bra.l S_fatanh_co68
+ bra.l S_facoth_co68
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_fsin_co68
+ bra.l S_fcos_co68
+ bra.l S_ftan_co68
+ bra.l S_fcot_co68
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_float81libnop
+ bra.l S_fasin_co68
+ bra.l S_facos_co68
+ bra.l S_fatan_co68
+ bra.l S_facot_co68
+
+S_float81libnop: rts
+
+;----------------------------------------------------------------------------
+
+ fpu on
+S_fadd_co68:
+ addq.l #1,_fadd_cnt.w
+ fmove.s d0,fp0
+ fadd.s d1,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fsub_co68:
+ addq.l #1,_fadd_cnt.w
+ fmove.s d0,fp0
+ fsub.s d1,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fmul_co68:
+ addq.l #1,_fmul_cnt.w
+ fmove.s d0,fp0
+ fsglmul.s d1,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fdiv_co68:
+ addq.l #1,_fdiv_cnt.w
+ fmove.s d0,fp0
+ fsgldiv.s d1,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fmul2_co68:
+ addq.l #1,_fmul_cnt.w
+ fmove.s d0,fp0
+ fscale.w d1,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fitof_co68:
+ fmove.l d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fftoi_co68:
+ fmove.s d0,fp0
+ fmove.l fp0,d0
+ rts
+
+
+S_fsqrt_co68:
+ addq.l #1,_fsqrt_cnt.w
+ fsqrt.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fabs_co68: bclr #31,d0 ; ganz einfach...
+ rts
+
+
+S_fcmp_co68:
+ fmove.s d0,fp0
+ fcmp.s d1,fp0
+ fbeq.l S_fcmp_coeq ; Variante 1:gleich
+ fbgt.l S_fcmp_cogt ; Variante 2:groeer
+
+ moveq #1,d0 ; Bedingung "kleiner"
+ cmp.w #2,d0 ; erzeugen
+ rts
+S_fcmp_cogt:
+ moveq #2,d0 ; Bedingung "groesser"
+ cmp.w #1,d0 ; erzeugen
+ rts
+S_fcmp_coeq:
+ cmp.w d0,d0 ; Bedingung "gleich"
+ rts ; erzeugen
+
+
+S_fexp_co68:
+ fetox.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fsinh_co68:
+ fsinh.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fcosh_co68:
+ fcosh.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_ftanh_co68:
+ ftanh.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fcoth_co68:
+ fmove.s d0,fp0
+ fsinh.x fp0,fp1
+ fcosh.x fp0
+ fsgldiv.x fp1,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fln_co68:
+ flogn.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_flog_co68:
+ flog10.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fasinh_co68:
+ fmove.s d0,fp0
+ fmove.x fp0,fp1
+ fmul.x fp1,fp0
+ fmovecr.x #CoConst1,fp2
+ fadd.x fp2,fp0
+ fsqrt.x fp0
+ fadd.x fp1,fp0
+ flogn.x fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_facosh_co68:
+ fmove.s d0,fp0
+ fmove.x fp0,fp1
+ fmul.x fp1,fp0
+ fmovecr.x #CoConst1,fp2
+ fsub.x fp2,fp0
+ fsqrt.x fp0
+ fadd.x fp1,fp0
+ flogn.x fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fatanh_co68:
+ fatanh.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_facoth_co68:
+ fmovecr.x #CoConst1,fp0
+ fdiv.s d0,fp0
+ fatanh.x fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fcos_co68:
+ fcos.s d0,fp0
+ fmove.x fp0,d0
+ rts
+
+
+S_fsin_co68:
+ fsin.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_ftan_co68:
+ ftan.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fcot_co68:
+ fsincos.s d0,fp0:fp1
+ fsgldiv.x fp1,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fatan_co68:
+ fatan.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_facot_co68:
+ fatan.s d0,fp1
+ fmovecr.x #CoConstPi,fp0
+ fscale.w #-1,fp0
+ fsub.x fp1,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_fasin_co68:
+ fasin.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+
+S_facos_co68:
+ facos.s d0,fp0
+ fmove.s fp0,d0
+ rts
+
+S_float81libend:
+
+ fpu off
+
diff --git a/tests/t_parsys/parsys.i68 b/tests/t_parsys/parsys.i68
new file mode 100644
index 0000000..e5a2569
--- /dev/null
+++ b/tests/t_parsys/parsys.i68
@@ -0,0 +1,115 @@
+; Includedatei PcPar-System
+; vor dem Programm mit include einbinden
+
+;----------------------------------------------------------------------------
+; offizieller Datenbereich:
+
+ shared S_RegSave,S_MemEnd,S_ParNo,S_CPUNo
+ shared _fadd_cnt,_fmul_cnt,_fdiv_cnt,_fsqrt_cnt
+
+ org $400
+S_MemEnd:
+ ds.l 1 ; Speicherende ( Default 64K )
+S_SysStart:
+ ds.l 1 ; Anfang des Systemcodes
+S_ParNo: ; vom PC geschiebene Werte
+ ds.w 1 ; Parallelrechneradresse
+S_LibAdr: ; Adresse der Library-
+ ds.l 1 ; sprungtabelle
+_fadd_cnt: ; Anzahl ausgefuehrter Gleit-
+ ds.l 1 ; kommaadditionen/subtraktion
+_fmul_cnt: ; dito Multiplikation
+ ds.l 1
+_fdiv_cnt: ; dito Division
+ ds.l 1
+_fsqrt_cnt: ; dito Quadratwurzel
+ ds.l 1
+S_FreeMemEnd:
+ ds.l 1 ; Ende freien Speichers
+S_CPUNo:
+ ds.w 1 ; CPU-Typ: 0 = 68008
+ ; 1 = 68000
+ ; 2 = 68010
+ ; 3 = 68020
+ ; 4 = 68030
+ ; Byte 1 : $01 = 68881
+ ; $02 = 68882
+ ; $10 = 68851
+ org $600
+
+S_SSPEnd:
+ ds.l 1 ; Anfang des Systemstacks
+S_ResVecSave: ; Sicherung Resetvektor
+ ds.l 1
+S_RegSave: ; Registersicherung
+ ds.l 17 ; wird vom PC veraendert
+S_ExVec: ; Exceptionvektor
+ ds.w 1
+S_LibStart:
+ ds.l 1 ; Anfang Librarykette
+ org $800
+
+;-----------------------------------------------------------------------------
+; Libraryoffsets :
+
+fadd equ $0000
+fsub equ $0004
+fmul equ $0008
+fdiv equ $000c
+fmul2 equ $0010
+fsqrt equ $0014
+fabs equ $0018
+
+fcmp equ $0020
+fitof equ $0024
+fftoi equ $0028
+
+fexp equ $0040
+fsinh equ $0044
+fcosh equ $0048
+ftanh equ $004c
+fcoth equ $0050
+
+fln equ $0060
+flog equ $0064
+fasinh equ $0068
+facosh equ $006c
+fatanh equ $0070
+facoth equ $0074
+
+fsin equ $0080
+fcos equ $0084
+ftan equ $0088
+fcot equ $008c
+
+fasin equ $00a0
+facos equ $00a4
+fatan equ $00a8
+facot equ $00ac
+
+;----------------------------------------------------------------------------
+; Konstanten fuer Betriebssystemaufrufe:
+
+TrapProgEnd equ 15 ; Trap fuer Programmende
+
+TrapTglSStep equ 14 ; Trap Einzelschritt an/aus
+
+TrapLibCtrl equ 13 ; Trap Libraryverwaltung
+LibCtrlInstall equ 0
+LibCtrlGetAdr equ 1
+
+;----------------------------------------------------------------------------
+; andere Konstanten:
+
+S_Latch equ $fffffffe ; Adresse der I/O-Latches
+
+is68008 equ $00 ; Prozessorcode 68008
+is68000 equ $01 ; " 68000
+is68010 equ $02 ; " 68010
+is68020 equ $03 ; " 68020
+is68030 equ $04 ; " 68030
+has68881 equ $01 ; " 68881
+has68882 equ $02 ; " 68882
+hasMMU equ $10 ; " 68851
+intMMU equ $20 ; " interne MMU
+
diff --git a/tests/t_parsys/t_parsys.asm b/tests/t_parsys/t_parsys.asm
new file mode 100644
index 0000000..8afe6f3
--- /dev/null
+++ b/tests/t_parsys/t_parsys.asm
@@ -0,0 +1,994 @@
+ include parsys.i68
+
+ page 60
+ cpu 68000
+
+;-----------------------------------------------------------------------------
+; Die Exceptionvektoren:
+
+ supmode on
+
+ org $00000000 ; Die Vektoren
+ dc.l 0 ; Adresse vom Stack (Dummy)
+ dc.l Start ; erster Start
+ dc.l ex_vec2 ; Busfehler
+ dc.l ex_vec3 ; Adressfehler
+ dc.l ex_vec4 ; Illegaler Befehl
+ dc.l ex_vec5 ; Division durch Null
+ dc.l ex_vec6 ; Befehl CHK
+ dc.l ex_vec7 ; Befehl TRAPV
+ dc.l ex_vec8 ; Privilegverletzung
+ dc.l StepProc ; Ablaufverfolgung
+ dc.l ex_vec10 ; Line-A --> Gleitkomma
+ dc.l S_LineF ; Line-F --> 68881-Emulator
+ dc.l ex_vec12 ; Reserviert
+ dc.l ex_vec13 ; Koprozessor-Protokollfehler
+ dc.l ex_vec14 ; illegaler FRESTORE-Frame
+ dc.l ex_vec15 ; nicht initialisierter Unterbrechungsvektor
+ dc.l ex_vec16 ; Reserviert
+ dc.l ex_vec17 ; Reserviert
+ dc.l ex_vec18 ; Reserviert
+ dc.l ex_vec19 ; Reserviert
+ dc.l ex_vec20 ; Reserviert
+ dc.l ex_vec21 ; Reserviert
+ dc.l ex_vec22 ; Reserviert
+ dc.l ex_vec23 ; Reserviert
+ dc.l ex_vec24 ; Unechte Unterbrechung
+ dc.l ex_vec25 ; autovektoriell 1
+ dc.l ex_vec26 ; autovektoriell 2
+ dc.l ex_vec27 ; autovektoriell 3
+ dc.l ex_vec28 ; autovektoriell 4
+ dc.l ex_vec29 ; autovektoriell 5
+ dc.l ex_vec30 ; autovektoriell 6
+ dc.l ex_vec31 ; autovektoriell 7
+ dc.l PcSysCall ; Trap #0 --> PC-Kommunikation
+ dc.l ex_vec33 ; Trap #1
+ dc.l ex_vec34 ; Trap #2
+ dc.l ex_vec35 ; Trap #3
+ dc.l ex_vec36 ; Trap #4
+ dc.l ex_vec37 ; Trap #5
+ dc.l ex_vec38 ; Trap #6
+ dc.l ex_vec39 ; Trap #7
+ dc.l ex_vec40 ; Trap #8
+ dc.l ex_vec41 ; Trap #9
+ dc.l ex_vec42 ; Trap #10
+ dc.l ex_vec43 ; Trap #11
+ dc.l ex_vec44 ; Trap #12
+ dc.l S_LibFun ; Trap #13 --> Libraryverwaltung
+ dc.l S_StepTgl ; Trap #14 --> Trace an/aus
+ dc.l S_ProgEnd ; Trap #15 --> Programmende
+ dc.l ex_vec48 ; BSUN in FPU gesetzt
+ dc.l ex_vec49 ; FPU inexaktes Ergebnis
+ dc.l ex_vec50 ; FPU Division durch 0
+ dc.l ex_vec51 ; FPU Unterlauf
+ dc.l ex_vec52 ; FPU Operandenfehler
+ dc.l ex_vec53 ; FPU Ueberlauf
+ dc.l ex_vec54 ; FPU signaling NAN
+ dc.l ex_vec55 ; reserviert
+ dc.l ex_vec56 ; MMU Konfigurationsfehler
+ dc.l ex_vec57 ; MMU Illegale Operation
+ dc.l ex_vec58 ; MMU Zugriffsfehler
+ ; Vektoren 59..255 frei
+
+;----------------------------------------------------------------------------
+; Installationssequenz:
+
+ org $800
+start:
+ clr.w S_Latch.w ; Port nullen
+
+ and.b #$fc,S_MemEnd+3.w ; Speichergroesse auf Lang-
+ ; wortadresse ausrichten
+ move.l S_MemEnd.w,a7 ; SSP setzen
+
+ lea -256(a7),a0 ; SSP-Anfang in A0
+ move.l a0,S_SSPEnd.w ; sichern
+
+ lea S_End.w,a1 ; Codelaenge berechnen
+ lea S_Start.w,a2
+ sub.l a2,a1 ; A1=Laenge Systemcode
+ moveq #4,d0 ; auf mehrfaches von 4 aus-
+ sub.w a1,d0 ; richten
+ and.l #3,d0
+ add.l d0,a1
+
+ sub.l a1,a0 ; Start des Systemcodes rechnen
+ move.l a0,S_SysStart.w ; sichern
+ move.l a0,$4.w ; =Programmstart
+
+ move.l a1,d0 ; Systemcode umkopieren
+ lsr.l #2,d0 ; =Zahl Langworttransfers
+ subq.w #1,d0 ; wg. DBRA
+S_SysCopy: move.l (a2)+,(a0)+
+ dbra d0,S_SysCopy
+
+ sub.l a2,a0 ; Verschiebedifferenz rechnen
+ move.l a0,d1
+
+ lea 8.w,a1 ; alle Vektoren relozieren
+ moveq #45,d0
+S_RelVec: add.l d1,(a1)+
+ dbra d0,S_RelVec
+
+ move.l S_SysStart.w,a1 ; obere Speichergrenze in USP...
+ move a1,usp
+ move.l a1,S_FreeMemEnd.w ; und Variable
+
+ move.l #-1,S_LibStart.w; Librarykette leer
+
+ lea S_floatlib.w,a0 ; passende FloatLib installieren
+ btst #0,S_Latch+1.w ; 68881 vorhanden ?
+ bne.s S_NoCo81
+ lea S_float81lib.w,a0 ; ja-->andere Library
+S_NoCo81: moveq #LibCtrlInstall,d0 ; einschreiben
+ trap #TrapLibCtrl
+
+ moveq #LibCtrlGetAdr,d0 ; Adresse holen
+ lea S_LibName.w,a0
+ trap #TrapLibCtrl
+ move.l d0,S_LibAdr.w
+
+ move.l 4*4.w,a4 ; Exceptionvektoren 4 und 11 retten
+ move.l 11*4.w,a5
+ move.l sp,a6 ; SP retten
+ move.l #S_NoCPU,4*4.w ; neue Exceptionhandler einschreiben
+ move.l #S_NoMMU,11*4.w
+ moveq #is68008,d1 ; Prozessorcode loeschen
+
+ cpu 68030 ; fuer zus. Befehle
+
+ ori #1,ccr ; 68008 ausfiltern
+ moveq #is68000,d1
+
+ movec vbr,d0 ; geht erst ab 68010
+ moveq #is68010,d1
+
+ extb d0 ; geht erst ab 68020
+ moveq #is68020,d1
+
+ cpu 68000 ; nicht mehr gebraucht
+ fpu on ; dafuer dies
+
+S_NoCPU: btst #0,S_Latch+1.w ; FPU vorhanden ?
+ bne.s S_NoFPU ; nein-->
+ or.w #has68881,d1 ; ja : 68881 annehmen
+ fnop ; FPU idle machen, damit im folgenden
+ fsave -(sp) ; ein idle frame gespeichert wird
+ cmp.b #$18,1(sp) ; Framelaenge=$18 fuer 68881, $38 fuer 882
+ beq.s S_NoFPU
+ add.w #(has68882-has68881),d1 ; 68882 eintragen
+
+ fpu off ; FPU nicht mehr gebraucht
+ pmmu on ; dafuer die MMU
+
+S_NoFPU: move.l a4,4*4.w ; Exception 4 zuruecksetzen
+ pflusha ; dies versteht auch die 68030-MMU
+ add.w #hasMMU,d1 ; gefunden: Flag dazu
+ move.l #S_SmallMMU,11*4.w ; testen ob Schmalspur-MMU
+ psave -(sp)
+ bra.s S_NoMMU ; Ergebnis 68020/68851
+
+S_SmallMMU: move.b #is68030,d1 ; 68030 eintragen (nicht MOVEQ!!)
+ add.w #(intMMU-hasMMU),d1 ; Code interne MMU
+
+S_NoMMU: move.l a5,11*4.w ; Line-F-Vektor zuruecksetzen
+ move.l a6,sp ; SP restaurieren
+ move.w d1,S_CPUNo.w ; Ergebnis einschreiben
+
+ trap #TrapProgEnd
+
+S_LibName: dc.b "FLOAT",0
+
+;----------------------------------------------------------------------------
+; Gleitkommalibrary, ohne 68881:
+
+ supmode off
+
+ include float.i68
+
+;----------------------------------------------------------------------------
+; Gleitkommalibrary, mit 68881:
+
+ supmode off
+
+ include float81.i68
+
+;----------------------------------------------------------------------------
+; Die Startsequenz:
+
+ supmode on
+
+S_Start: clr.w S_Latch.w ; Ports loeschen
+ clr.l _fadd_cnt.w ; Zielvariablen loeschen
+ clr.l _fmul_cnt.w
+ clr.l _fdiv_cnt.w
+ clr.l _fsqrt_cnt.w
+
+ move.l S_MemEnd.w,d0 ; SSP an Speicherende legen
+ move.l d0,$0.w ; Neben Resetvekor vermerken
+ move.l d0,a7 ; SSP setzen
+ move.l S_FreeMemEnd.w,a0 ; USP liegt am Speicherende
+ move a0,usp
+
+ andi #$dfff,sr ; In Usermodus schalten
+ jmp Start.w ; zum Programmstart
+
+;----------------------------------------------------------------------------
+; Die Ausnahmebehandlungsprozeduren:
+
+ex_vec2:
+ move.w #2,S_ExVec.w
+ bra.l ex_handle
+ex_vec3:
+ move.w #3,S_ExVec.w
+ bra.l ex_handle
+ex_vec4:
+ move.w #4,S_ExVec.w
+ bra.l ex_handle
+ex_vec5:
+ move.w #5,S_ExVec.w
+ bra.l ex_handle
+ex_vec6:
+ move.w #6,S_ExVec.w
+ bra.l ex_handle
+ex_vec7:
+ move.w #7,S_ExVec.w
+ bra.l ex_handle
+ex_vec8:
+ move.w #8,S_ExVec.w
+ bra.l ex_handle
+ex_vec10:
+ move.w #10,S_ExVec.w
+ bra.l ex_handle
+ex_vec11:
+ move.w #0,S_Control+S_Response.w ; FPU resetten
+ move.w #11,S_ExVec.w
+ bra.l ex_handle
+ex_vec12:
+ move.w #12,S_ExVec.w
+ bra.l ex_handle
+ex_vec13:
+ move.w #13,S_ExVec.w
+ bra.l ex_handle
+ex_vec14:
+ move.w #14,S_ExVec.w
+ bra.l ex_handle
+ex_vec15:
+ move.w #15,S_ExVec.w
+ bra.l ex_handle
+ex_vec16:
+ move.w #16,S_ExVec.w
+ bra.l ex_handle
+ex_vec17:
+ move.w #17,S_ExVec.w
+ bra.l ex_handle
+ex_vec18:
+ move.w #18,S_ExVec.w
+ bra.l ex_handle
+ex_vec19:
+ move.w #19,S_ExVec.w
+ bra.l ex_handle
+ex_vec20:
+ move.w #20,S_ExVec.w
+ bra.l ex_handle
+ex_vec21:
+ move.w #21,S_ExVec.w
+ bra.l ex_handle
+ex_vec22:
+ move.w #22,S_ExVec.w
+ bra.l ex_handle
+ex_vec23:
+ move.w #23,S_ExVec.w
+ bra.l ex_handle
+ex_vec24:
+ move.w #24,S_ExVec.w
+ bra.l ex_handle
+ex_vec25:
+ move.w #25,S_ExVec.w
+ bra.l ex_handle
+ex_vec26:
+ move.w #26,S_ExVec.w
+ bra.l ex_handle
+ex_vec27:
+ move.w #27,S_ExVec.w
+ bra.l ex_handle
+ex_vec28:
+ move.w #28,S_ExVec.w
+ bra.l ex_handle
+ex_vec29:
+ move.w #29,S_ExVec.w
+ bra.l ex_handle
+ex_vec30:
+ move.w #30,S_ExVec.w
+ bra.l ex_handle
+ex_vec31:
+ move.w #31,S_ExVec.w
+ bra.l ex_handle
+ex_vec33:
+ move.w #33,S_ExVec.w
+ bra.l ex_handle
+ex_vec34:
+ move.w #34,S_ExVec.w
+ bra.l ex_handle
+ex_vec35:
+ move.w #35,S_ExVec.w
+ bra.l ex_handle
+ex_vec36:
+ move.w #36,S_ExVec.w
+ bra.l ex_handle
+ex_vec37:
+ move.w #37,S_ExVec.w
+ bra.l ex_handle
+ex_vec38:
+ move.w #38,S_ExVec.w
+ bra.l ex_handle
+ex_vec39:
+ move.w #39,S_ExVec.w
+ bra.l ex_handle
+ex_vec40:
+ move.w #40,S_ExVec.w
+ bra.l ex_handle
+ex_vec41:
+ move.w #41,S_ExVec.w
+ bra.l ex_handle
+ex_vec42:
+ move.w #42,S_ExVec.w
+ bra.l ex_handle
+ex_vec43:
+ move.w #43,S_ExVec.w
+ bra.l ex_handle
+ex_vec44:
+ move.w #44,S_ExVec.w
+ bra.l ex_handle
+ex_vec48:
+ move.w #48,S_ExVec.w
+ bra.l ex_handle
+ex_vec49:
+ move.w #49,S_ExVec.w
+ bra.l ex_handle
+ex_vec50:
+ move.w #50,S_ExVec.w
+ bra.l ex_handle
+ex_vec51:
+ move.w #51,S_ExVec.w
+ bra.l ex_handle
+ex_vec52:
+ move.w #52,S_ExVec.w
+ bra.l ex_handle
+ex_vec53:
+ move.w #53,S_ExVec.w
+ bra.l ex_handle
+ex_vec54:
+ move.w #54,S_ExVec.w
+ bra.l ex_handle
+ex_vec55:
+ move.w #55,S_ExVec.w
+ bra.l ex_handle
+ex_vec56:
+ move.w #56,S_ExVec.w
+ bra.l ex_handle
+ex_vec57:
+ move.w #57,S_ExVec.w
+ bra.l ex_handle
+ex_vec58:
+ move.w #58,S_ExVec.w
+
+ex_handle:
+ movem.l d0-d7/a0-a7,S_RegSave.w ; Wert der Register abspeichern
+ move usp,a0
+ move.l a0,S_RegSave+64.w
+ lea S_Latch.w,a0
+ move.w S_ExVec.w,d0 ; Vektornr. holen
+ move.b d0,1(a0) ; Fehlernr. ausgeben
+ex_infinite:
+ move.b d0,d1 ; Die LED n-mal blinken lassen ; Die LED n-mal blinken lassen
+ex_blink:
+ bset #0,(a0) ; LED an
+ bsr.s ex_wait
+ bclr #0,(a0) ; LED aus
+ bsr.s ex_wait
+ subq.b #1,d1
+ bne.s ex_blink
+ move.b #$05,d1 ; eine Pause einlegen
+ex_pause:
+ bsr.s ex_wait
+ subq.b #1,d1
+ bne.s ex_pause
+ bra.s ex_handle ; und alles von vorne
+
+ex_wait:
+ move.l d0,-(a7) ; Register retten
+ move.l #$50000,d0 ; ungefaehr 1/2 Sekunde
+ex_wloop: ; Register herunterzaehlen
+ subq.l #1,d0
+ bne.s ex_wloop
+ move.l (a7)+,d0 ; D0 wieder zurueck
+ rts
+
+;----------------------------------------------------------------------------
+; Einzelschrittverfolgung:
+
+StepProc:
+ clr.b S_Latch+1.w
+ movem.l d0-d7/a0-a7,S_RegSave.w ; Register retten
+ move usp,a0
+ move.l a0,S_RegSave+64.w
+ move.l $4.w,S_ResVecSave.w ; Resetvektor sichern
+ lea S_Restart(pc),a0 ; am Punkt S_StepBack wacht
+ move.l a0,$4.w ; der PcPar wieder auf
+ move.b #9,S_Latch+1.w ; ParMon-Aufruf ausgeben
+ stop #$2000 ; hier geht es nur mit einem
+ ; Reset weiter
+
+;----------------------------------------------------------------------------
+; Routinen zur Kommunikation mit dem PC (Trap 0)
+
+PcSysCall:
+ clr.b S_Latch+1.w
+ movem.l d0-d7/a0-a7,S_RegSave.w ; Register retten
+ move usp,a0
+ move.l a0,S_RegSave+64.w
+ move.l $4.w,S_ResVecSave.w ; Resetvektor sichern
+ lea S_Restart(pc),a0 ; am Punkt S_Restart wacht
+ move.l a0,$4.w ; der PcPar wieder auf
+ move.b #$40,S_Latch+1.w ; PC-Aufruf ausgeben
+ stop #$2000 ; hier geht es nur mit einem
+
+S_Restart:
+ clr.b S_Latch+1.w ; Systemanfrage loeschen
+ move.l S_ResVecSave.w,$4.w ; Resetvektor zurueck
+ move.l S_RegSave+64.w,a0
+ move a0,usp
+ movem.l S_RegSave.w,d0-d7/a0-a7 ; Register zurueckholen
+ rte ; das war's
+
+;----------------------------------------------------------------------------
+; Libraryverwaltung : Trap #13
+;
+; Struktur einer Library :
+;
+; Adresse 0: Laenge in Bytes (1 <= Laenge <= 256k)
+; Adresse 4: Dummyzeiger =-1 (vom System verwendet) \
+; Adresse 8: Libraryname als ASCIIZ-String | kopierter Block
+; Adresse n: Sprungtabelle |
+; Adresse m: Librarycode, private Daten /
+;
+; der gesamte Librarycode muss lageunabhaengig geschrieben sein !
+;
+; definierte Unterfunktionen:
+;
+; D0.L=0 : Library installieren
+; D0.L=1 : Libraryzeiger holen
+;
+;----------------------------------------------------------------------------
+
+; Subfunktion 0: Library von Adresse 0 installieren:
+; Eingabe: A0=Startadresse der Library
+; Ausgabe: keine
+
+S_LibFun: movem.l d1-d2/a1-a2,-(a7) ; Register sichern
+ tst.l d0 ; ist es Funktion 0 ?
+ bne.s S_LibFun1 ; nein-->bei Funktion 1 weitertesten
+
+ move.l (a0),d0 ; Laenge Library holen
+ addq.l #3,d0 ; auf Doppelworte aufrunden
+ and.b #$fc,d0
+ moveq #1,d1
+ cmp.l #$40000,d0 ; Maximalgroesse ueberschritten ?
+ bge.l S_LibErr ; ja-->Ende mit Fehler Nr.1
+
+ move usp,a1 ; Userstack holen
+ move.l S_FreeMemEnd.w,d2 ; mom. belegte Stackmenge berechnen
+ sub.l a1,d2
+ move.l a1,a2 ; neue Untergrenze in A2 rechnen
+ sub.l d0,a2
+ moveq #2,d1
+ cmp.l #$800,a2 ; unter abs. Untergrenze gesunken ?
+ ble.l S_LibErr ; ja-->Ende mit Fehler Nr.2
+
+ move a2,usp ; neuen Userstack einschreiben
+ lsr.l #1,d2 ; Stackgroesse in Worten
+ bra.s S_LibStckEnd ; damit Ende, falls kein Stack belegt
+
+S_LibStckCpy: move.w (a1)+,(a2)+ ; Userstack umkopieren
+S_LibStckEnd: dbra d2,S_LibStckCpy
+
+ move.l S_FreeMemEnd.w,a1 ; Startadresse der Library rechnen
+ sub.l d0,a1 ; =altes Speicherende-Laenge
+ addq.l #4,a0 ; Quellzeiger weitersetzen
+ move.l S_LibStart.w,d1 ; bisheriges Ende der Kette holen
+ move.l d1,(a0) ; in neue Library eintragen
+ move.l a1,S_FreeMemEnd.w ; Speichergrenze heruntersetzen
+ move.l a1,S_LibStart.w ; neuen Kettenanfang eintragen
+
+ lsr.l #2,d0 ; Laenge in Doppelworte umrechnen
+ subq.w #1,d0 ; wg. DBRA
+
+S_LibInstLoop: move.l (a0)+,(a1)+ ; Library umkopieren
+ dbra d0,S_LibInstLoop
+
+ bra.l S_LibOK ; Ende ohne Fehler
+
+; Subfunktion 1: Library finden, deren Name ab (A0) als ASCIIZ steht:
+; Eingabe: A0=Startadresse des ASCIIZ-Strings
+; Ausgabe: D0=Startadresse der Sprungtabelle
+
+S_LibFun1: subq.l #1,d0 ; ist es Funktion 1 ?
+ bne.s S_LibFun2 ; nein-->bei Funktion 2 weitertesten
+
+ move.l S_LibStart.w,a2 ; Wurzelzeiger der Kette holen
+
+S_LibGetLoop: moveq #3,d1 ; Kettenende erreicht ?
+ move.l a2,d0
+ addq.l #1,d0 ; wird durch -1 angezeigt
+ beq.l S_LibErr ; ja-->Ende mit Fehler
+
+ move.l a0,d0 ; Startadresse Vergleichsstring retten
+ lea 4(a2),a1 ; A1 zeigt auf zu testenden Namen
+S_LibGetComp: cmpm.b (a0)+,(a1)+ ; ein Zeichen vergleichen
+ bne.s S_LibGetNext ; ungleich-->weiter in Kette
+ tst.b -1(a0) ; War das das Ende ?
+ beq.s S_LibGetFnd ; ja-->Heureka!
+ bra.s S_LibGetComp ; ansonsten naechstes Zeichen vergleichen
+
+S_LibGetNext: move.l (a2),a2 ; weiter auf Nachfolger in Kette
+ move.l d0,a0 ; A0 auf Referenzstringanfang
+ bra.s S_LibGetLoop
+
+S_LibGetFnd: move.l a1,d0 ; Libraryadresse gerade machen
+ addq.l #1,d0
+ bclr #0,d0
+
+ bra.l S_LibOK ; Ende ohne Fehler
+
+S_LibFun2: moveq #127,d1 ; unbekannte Funktion:
+ bra.l S_LibErr
+
+S_LibErr: move.l d1,d0 ; Fehlercode in D0 holen
+ movem.l (a7)+,d1-d2/a1-a2 ; Register zurueck
+ or.b #1,1(a7) ; Carry setzen
+ rte
+
+S_LibOK: movem.l (a7)+,d1-d2/a1-a2 ; Register zurueck
+ and.b #$fe,1(a7) ; Carry loeschen
+ rte
+
+;----------------------------------------------------------------------------
+; Tracemode ein/aus:
+
+S_StepTgl:
+ andi #$7fff,sr ; bitte hier kein Trace!
+ bclr #7,(a7) ; altes T-Flag loeschen
+ btst #0,1(a7)
+ bne.s S_StepOn ; C=1-->Tracemodus an
+ rte ; C=0-->fertig
+S_StepOn:
+ bset #7,(a7) ; T-Flag setzen
+ rte
+
+;----------------------------------------------------------------------------
+; Programmende (Trap 15)
+
+S_ProgEnd: lea S_Start(pc),a0 ; Startvektor zurueck
+ move.l a0,4.w
+ move.b #$ff,S_Latch+1.w ; "Ich bin fertig"
+ stop #$2000 ; und Ende
+
+;----------------------------------------------------------------------------
+; Line-F-Exception
+
+S_Response equ $fffffe00 ; In a6 (Coprozessor-Register)
+S_Control equ $02 ; Alle weiteren Register relativ
+S_Save equ $04 ; zu "Response"
+S_Restore equ $06
+S_Command equ $0a ; in a5
+S_Condition equ $0e
+S_Operand equ $10 ; in a4
+S_Reg_Selec equ $14
+S_Ins_Add equ $18
+
+ supmode on
+
+S_LineF: btst #0,S_Latch+1.w ; Ist ein Koprozessor vorhanden ?
+ bne ex_vec11 ; nein-->normaler Line-F
+
+ movem.l d0-d7/a0-a6,S_RegSave.w ; Register retten
+ move.l usp,a0 ; USP retten
+ move.l a0,S_RegSave+60.w ; (geht nur ueber Umweg)
+ lea S_Response.w,a6 ; #response nach A6
+ lea S_Command(a6),a5 ; #command nach A5
+ lea S_Operand(a6),a6 ; #operand nach A4
+ lea S_RegSave.w,a3 ; #dregs nach A3
+ move.l 2(a7),a0 ; PC nach A0
+ move.w (a0),d1 ; Kommando nach D1
+S_again: ; Einsprung fuer weitere FPU-Befehle
+ and.w #%0000000111000000,d1 ; Spezialteil ausmaskieren
+ bne S_spezial ; Ein Bit gesetzt-->Spezialbefehl
+ move.w 2(a0),d1 ; zweiten Befehlsteil in D1 merken
+ move.w d1,(a5) ; Befehl in FPU schr. (A5==#command)
+S_do_ca: ; Einsprung fuer weitere Nachfragen an FPU
+ move.w (a6),d0 ; Response lesen
+ btst #12,d0 ; Erstes Modusbit testen
+ bne S_rw_1x ; ==1 --> springen
+ btst #11,d0 ; Zweites Modusbit testen
+ beq.s S_rw_00 ; ==0 --> springen
+; ----- %xxx01, Null-Primitive/Transfer Single CPU Register
+ btst #10,d0 ; Register uebertragen ?
+ bne.s S_rw_sngl ; Ja--> Transfer Single CPU-Register
+ btst #15,d0 ; CA (Come Again) gesetzt ?
+ bne.s S_do_ca ; Ja--> weiter fragen, sonst fertig
+ addq.l #4,a0 ; A0 um reine Befehlslaenge 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 S_again ; Ja-->direkt weitermachen
+ move.l a0,2(a7) ; Neuen PC eintragen
+ move.l S_RegSave+60.w,a0 ; USP wiederherstellen
+ move.l a0,usp ; (geht nur ueber Umweg)
+ movem.l (a3),d0-a6 ; Register wiederherstellen
+ rte ; Trap beenden
+S_rw_sngl:
+ and.w #%1110000,d1 ; Registernummer ausmaskieren ( nur Dn )
+ lsr.w #2,d1 ; D1=Nummer*4
+ move.l 0(a3,d1.w),(a4) ; Register uebertragen (a4==#operand, a3==#dregs)
+ bra.s S_do_ca ; danach kommt immer noch etwas
+;-----%xxx00, Transfer multiple coprocessor Reg.
+S_rw_00:
+ bsr S_calc_add ; Operandenadresse nach A1 holen
+ move.w S_Reg_Selec(a6),d4 ; Registerliste nach D4 holen
+ btst #13,d0 ; Dr-Bit testen
+ beq.s S_w_00 ; ==0--> Daten in FPU schreiben
+ btst #12,d0 ; Predekrementmodus ?
+ beq.s S_r_pred ; ==0--> Ja,springen
+ moveq #7,d0 ; Schleifenzaehler fuer 8 Bits
+S_11:
+ lsl.w #1,d4 ; Ein Bit ins Carry
+ bcc.s S_21 ; nur bei Bit==1 etwas machen
+ move.l (a4),(a1)+ ; 1 (A4==#operand)
+ move.l (a4),(a1)+ ; 2
+ move.l (a4),(a1)+ ; 3 Langworte fuer jedes Register
+S_21:
+ dbra d0,S_11 ; Fuer alle 8 Bits
+ bra.s S_do_ca ; Nochmal FPU befragen
+S_r_Pred:
+ moveq #7,d0 ; Schleifenzaehler fuer 8 Bits
+S_12:
+ lsl.w #1,d4 ; Ein Bit ins Carry
+ bcc.s S_22 ; nur bei Bit=1 etwas machen
+ move.l (a4),(a1)+ ; 1 (A4==#operand)
+ move.l (a4),(a1)+ ; 2
+ move.l (a4),(a1)+ ; 3 Langworte fuer jedes Register
+ suba.w #24,a1 ; Dekrement durchfuehren
+S_22:
+ dbra d0,S_12 ; Fuer alle 8 Bits
+ adda.w #12,a1 ; A1 wieder auf letztes Register
+ move.l a1,(a2) ; A1 als Registerinhalt abspeichern
+ bra S_do_ca ; Nochmal FPU befragen
+S_w_00:
+ move.w (a0),d0 ; erstes Befehlswort holen
+ and.b #%111000,d0 ; Adressierungsart maskieren
+ cmp.b #%011000,d0 ; Gleich (An)+ ?
+ beq.s S_w_Post ; Ja-->Postinkrementiermodus
+ moveq #7,d0 ; Schleifenzaehler fuer 8 Bits
+S_13:
+ lsl.w #1,d4 ; Ein Bit ins Carry
+ bcc.s S_23 ; Nur bei Bit==1 etwas machen
+ move.l (a1)+,(a4) ; 1 (A4==#operand)
+ move.l (a1)+,(a4) ; 2
+ move.l (a1)+,(a4) ; 3 Langworte fuer jedes Register
+S_23:
+ dbra d0,S_13 ; Fuer alle 8 Bits
+ bra S_do_ca ; Nochmal FPU befragen
+S_w_Post:
+ suba.w #12,a1 ; Inkrement von calc_add aufheben
+ moveq #7,d0 ; Schleifenzaehler fuer 8 Bits
+S_14:
+ lsl.w #1,d4 ; Ein Bit ins Carry
+ bcc.s S_24 ; nur bei Bit==1 etwas machen
+ move.l (a1)+,(a4) ; 1 (A4==#operand)
+ move.l (a1)+,(a4) ; 2
+ move.l (a1)+,(a4) ; 3 Langworte fuer jedes Register
+S_24:
+ dbra d0,S_14 ; Fuer alle 8 Bits
+ move.l a1,(a2) ; A1 als Registerinhalt abspeichern
+ bra S_do_ca ; Nochmal FPU befragen
+
+S_rw_1x:
+ btst #11,d0 ; zweites Modusbit testen
+ bne.s S_rw_11 ; ==1 --> springen (Trap,Error)
+ btst #13,d0 ; DR-Bit testen
+ beq.s S_w_10 ; ==0 --> Daten an FPU schreiben
+;----- %xx110, evaluate effective adress and transfer data
+ bsr S_calc_add ; Operandenadresse berechnen
+ ; A1=Operandenadresse, d1.l=Operandenl„nge
+ cmp.w #2,d1 ; Laenge-2
+ ble.s S_r_bw ; <=2 --> Wort-oder-Byteoperand
+S_r_11:
+ move.l (a4),(a1)+ ; ein Langwort lesen (A4==#operand)
+ subq.l #4,d1 ; und runterzaehlen
+ bgt.s S_r_11 ; >0 --> weiter uebertragen
+ bra S_do_ca ; Nochmal FPU befragen
+S_r_bw:
+ btst #0,d1 ; Byte ?
+ bne.s S_r_byte ; Ja!
+ move.w (a4),(a1) ; Wort-Operand lesen (A4==#operand)
+ bra S_do_ca ; Nochmal FPU befragen
+S_r_byte:
+ move.b (a4),(a1) ; Byte-Operand lesen (A4==#operand)
+ bra.l S_do_ca ; Nochmal FPU befragen
+
+;----- %xx101, evaluate effective adress and transfer data
+S_w_10:
+ bsr S_calc_add ; Operandenadresse berechnen
+ ; A1=Operandenadresse, d1.l=Operandenl„nge
+ cmp.w #2,d1 ; Laenge-2
+ ble.s S_w_bw ; <=2 --> Wort-oder-Byteoperand
+S_w_11:
+ move.l (a1)+,(a4) ; ein Langwort lesen (A4==#operand)
+ subq.l #4,d1 ; und runterzaehlen
+ bgt.s S_w_11 ; >0 --> weiter uebertragen
+ bra S_do_ca ; Nochmal FPU befragen
+S_w_bw:
+ btst #0,d1 ; Byte ?
+ bne.s S_w_byte ; Ja!
+ move.w (a1),(a4) ; Wort-Operand lesen (A4==#operand)
+ bra S_do_ca ; Nochmal FPU befragen
+S_w_byte:
+ move.b (a1),(a4) ; Byte-Operand lesen (A4==#operand)
+ bra.l S_do_ca ; Nochmal FPU befragen
+
+;----- %xxx11, take pre-instruction exception
+S_rw_11:
+ bra ex_vec11 ; Error-Handler anspringen
+; ( hier koennte man eine genauere Fehleranalyse machen )
+
+S_spezial: ; Sprungbefehle etc.
+ cmp.w #%001000000,d1 ; FScc,FDBcc oder FTRAPcc
+ beq.s S_s_trap
+ cmp.w #%010000000,d1 ; Branch mit 16-Bit-Offset
+ beq.l S_s_br16
+ cmp.w #%011000000,d1 ; Branch mit 32-Bit-Offset
+ beq.l S_s_br32
+ bra ex_vec11 ; FSAVE/FRESTORE nicht unterstuetzt
+S_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_s_fdbcc ; Ja-->springen
+ cmp.w #%111000,d0 ; FTRAP ?
+ beq ex_vec11 ; Ja-->Fehler (nicht unterstuetzt)
+ ; sonst FScc
+ move.w 2(a0),S_condition(a6) ; Bedingung an FPU schicken
+ moveq #1,d0 ; Operandenlaenge=1 (fuer calc_add)
+ bsr S_calc_add ; Operandenadresse berechnen
+S_15:
+ move.w (a6),d0 ; Response lesen
+ btst #8,d0 ; IA-Bit testen
+ beq.s S_25 ; ==0 --> fertig
+ and.w #%1100000000000,d0 ; Bits 11 und 12 ausmaskieren
+ eor.w #%1100000000000,d0 ; Beide gesetzt ?
+ bne.s S_15 ; Nicht beide==1 --> warten
+ bra ex_vec11 ; Sonst ist Exception aufgetreten
+S_25:
+ btst #0,d0 ; Antwortbit testen
+ sne (a1) ; Je nach Bit setzen/loeschen
+ bra S_do_ca ; Nochmal FPU befragen
+S_s_fdbcc:
+ move.w 2(a0),S_condition(a6) ; Bedingung an FPU schicken
+ and.w #%111,d1 ; Registernummer maskieren (D1=(A0))
+ lsl.w #2,d1 ; D1=Nummer*4
+ lea 0(a3,d1.w),a1 ; A1 enthaelt Adresse des Datenreg.
+ move.l (a1),d1 ; Dn holen
+ subq.w #1,d1 ; Dn=Dn-1
+ move.l d1,(a1) ; Dn zurueckschreiben
+ move.l a0,a2 ; alten PC nach A2 holen
+ addq.l #2,a0 ; PC 2 weiter ( fuer "nicht springen")
+S_16:
+ move.w (a6),d0 ; Response lesen
+ btst #8,d0 ; IA-Bit testen
+ beq.s S_26 ; ==0 --> fertig
+ and.w #%1100000000000,d0 ; Bits 11 und 12 ausmaskieren
+ eor.w #%1100000000000,d0 ; Beide gesetzt ?
+ bne.s S_16 ; Nicht beide==1 --> warten
+ bra ex_vec11 ; Sonst ist Exception aufgetreten
+S_26:
+ btst #0,d0 ; Antwortbit testen
+ bne S_do_ca ; True-->das war's schon
+ adda.w 2(a2),a2 ; 16-Bit-Sprungdist. add. (A2=PC)
+ addq.w #1,d1 ; Dn=-1 ?
+ beq S_do_ca ; Ja-->kein Sprung (Schleifenende)
+ move.l a2,a0 ; Sonst "Sprung" (neuen PC laden)
+ bra S_do_ca ; nochmal FPU befragen
+S_s_br16:
+ move.w (a0),S_Condition(a6) ; Bedingung an FPU schicken
+S_17:
+ move.w (a6),d0 ; Response lesen
+ btst #8,d0 ; IA-Bit testen
+ beq.s S_27 ; ==0 --> fertig
+ and.w #%1100000000000,d0 ; Bits 11 und 12 ausmaskieren
+ eor.w #%1100000000000,d0 ; Beide gesetzt ?
+ bne.s S_17 ; Nicht beide==1 --> warten
+ bra ex_vec11 ; Sonst ist Exception aufgetreten
+S_27:
+ btst #0,d0 ; Antwortbit testen
+ beq S_do_ca ; False--> das war's schon
+ adda.w 2(a0),a0 ; 16-Bit-Sprungdistanz addieren
+ subq.l #2,a0 ; Ein Wort zurueck ( weil spaeter
+ ; noch 4 addiert wird und und nur 2 addiert werden muesste )
+ bra S_do_ca ; Nochmal FPU befragen
+S_s_br32:
+ move.w (a0),S_Condition(a6) ; Bedingung an FPU schicken
+S_18:
+ move.w (a6),d0 ; Response lesen
+ btst #8,d0 ; IA-Bit testen
+ beq.s S_28 ; ==0 --> fertig
+ and.w #%1100000000000,d0 ; Bits 11 und 12 ausmaskieren
+ eor.w #%1100000000000,d0 ; Beide gesetzt ?
+ bne.s S_18 ; Nicht beide==1 --> warten
+ bra ex_vec11 ; Sonst ist Exception aufgetreten
+S_28:
+ addq.l #2,a0 ; Befehl ist 3 Worte lang
+ ; (jetzt : (A0)=Distanz)
+ btst #0,d0 ; Antwortbit testen
+ beq S_do_ca ; False--> das war's schon
+ adda.l (a0),a0 ; 32-Bit-Sprungdistanz addieren
+ subq.l #4,a0 ; Zwei Worte zurueck ( weil spaeter
+ ; noch 4 addiert wird, 2 wurden schon addiert )
+ bra S_do_ca ; Nochmal FPU befragen
+S_calc_add:
+ ; Operandenadresse berechnen. A0 muss die Adresse des Line-F-
+ ; Befehls enthalten, D0 im unteren Byte die Operandenlaenge.
+ ; die zu berechnende Adresse wird in A1 abgelegt. A0 wird
+ ; um die Laenge der zusaetzlichen Daten erhaelt.
+ ; Zusaetzlich wird in D1 die Laenge des Operanden zurueckge-
+ ; geben (in Bytes, als Langwort). D2,D3,A3 werden zerstoert.
+ ; Bei den Adressierungsarten -(An),(An)+ steht in A2 ein
+ ; Zeiger auf die Stelle, in der der Inhalt des Adressregisters
+ ; gisters An steht (wird fuer FMOVEM gebraucht).
+
+ clr.l d1 ; Laenge als Langwort loeschen
+ move.b d0,d1 ; und Byte umkopieren
+ move.w (a0),d2 ; erstes Befehlswort nach D2
+ move.w d2,d3 ; und D3 retten
+ and.w #%111000,d3 ; Adressierungsart ausmaskieren
+ lsr.w #1,d3 ; D3=Adressierungsart*4 (Langworte)
+ lea S_cs_tab(pc),a1 ; Sprungtabellenadresse nach A1
+ move.l 0(a1,d3.w),a1 ; Adresse der Routine nach A1
+ jmp (a1) ; und Routine anspringen
+S_c_drd: ; %000 Data Register Direct: Dn
+S_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 fuer Daten-,1 fuer Adressregister )
+ lsl.w #2,d2 ; D2="Registernummer"*4 (+Modusbit)
+ addq.w #4,d2 ; +4 (fuer Operandenlaenge)
+ sub.w d1,d2 ; Wahre Laenge abziehen
+ adda.w d2,a1 ; Offset auf Registerfeldanfang add.
+ rts
+S_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
+S_c_arpo: ; %011 Adressregister indirect 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
+ move.l (a2),a1 ; Adresse (Inhalt A.-Reg.) nach A1
+ btst #0,d1 ; D1 ungerade ? (Byteoperand)
+ bne.s S_29 ; Ja-->Spezialbehandlung
+S_19:
+ add.l d1,(a2) ; Inkrement durchfuehren
+ rts
+S_29:
+ cmp.w #4*7,d2 ; Ist A7 gemeint ?
+ bne.s S_19 ; nein-->normal vorgehen
+ addq.l #2,(a2) ; Sonst (bei Byte) 2 addieren,
+ rts ; damit Stack gerade bleibt!
+S_c_arpr: ; %100 Adressregister Indirect with Predekrement: -(An)
+ and.w #%111,d2 ; Registernummer ausmaskieren
+ lsl.w #2,d2 ; D2=Registernummer*4
+ lea 32(a3,d2.w),a2 ; Adresse des Adressreg. nach A2
+ btst #0,d1 ; D1 ungerade? (Byteoperand)
+ bne.s S_210 ; Ja-->Spezialbehandlung
+S_110:
+ sub.l d1,(a2) ; Dekrement durchfuehren
+ move.l (a2),a1 ; Adresse (Inhalt des A.-Reg) nach A1
+ rts
+S_210:
+ cmp.w #4*7,d2 ; Ist A7 gemeint?
+ bne.s S_110 ; nein-->normal vorgehen
+ subq.l #2,(a2) ; Sonst (bei Byte) 2 addieren,
+ ; damit Stack gerade bleibt !
+ move.l (a2),a1 ; Adresse (Inhalt des A.-Reg) nach A1
+ rts
+S_c_ar16: ; %101 Addressregister Indirect with Displacement: d16(An)
+ and.w #%111,d2 ; Registernummer ausmaskieren
+ lsl.w #2,d2 ; D2=Registernummer*4
+ move.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
+S_c_ar08: ; %110 Addressregister Indirect with Index : d8(An,Xn)
+ and.w #%111,d2 ; Registernummer ausmaskieren
+ lsl.w #2,d2 ; D2=Registernummer*4
+ move.l 32(a3,d2.w),a1 ; Adresse nach A1
+ move.w 4(a0),d2 ; 3.Befehlswort nach D2 (Byte-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 S_c_ar81
+ and.w #%1111000000000000,d2 ; Nummer von Dn und Modusbit
+ lsr.w #5,d2 ; maskieren
+ lsr.w #5,d2 ; D2=Registernummer*4 (und modusbit)
+ adda.w 2(a3,d2.w),a1 ; 16-Bit-Index auf A1 addieren
+ addq.l #2,a0 ; A0 ein Wort (Kram & d8) weiter
+ rts
+S_c_ar81:
+ and.w #%1111000000000000,d2 ; Nummer von Dn und Modusbit
+ lsr.w #5,d2 ; maskieren
+ lsr.w #5,d2 ; D2=Registernummer*4 (und modusbit)
+ adda.w 0(a3,d2.w),a1 ; 32-Bit-Index auf A1 addieren
+ addq.l #2,a0 ; A0 ein Wort (Kram & d8) weiter
+ rts
+S_c_pc: ; %111 absolut short/long, PC-relativ (ohne/mit Index) \ oder direkt
+ btst #2,d2 ; Immidiate ?
+ bne.s S_immi ; <>0 --> Ja!
+ btst #1,d2 ; PC-relativ ?
+ bne.s S_pc_rel ; <>0 --> Ja!
+ btst #0,d2 ; Long ?
+ bne.s S_c_long ; <>0 --> Ja!
+ ; sonst short
+ move.w 4(a0),d2 ; Wortadresse holen
+ ext.l d2 ; Auf Langwort erweitern
+ move.l d2,a1 ; und als Operandenadresse merken
+ addq.l #2,a0 ; A0 ein Wort (Short-A.) weiter
+ rts
+S_c_long:
+ move.l 4(a0),a1 ; Langwortadresse holen
+ addq.l #4,a0 ; A0 zwei Worte (Long-A.) weiter
+ rts
+S_immi:
+ move.l a0,a1 ; Befehlsadresse nach A1
+ add.l d1,a0 ; A0 ueber Operand hinwegsetzen
+ rts
+S_pc_rel:
+ btst #0,d2 ; mit Index ?
+ bne.s S_pc_idx ; <>0 --> Ja!
+ move.l a0,a1 ; PC nach A1
+ adda.w 4(a0),a1 ; Offset addieren
+ addq.l #4,a1 ; +4 fuer Laenge des FPU-Befehls
+ addq.l #2,a0 ; A0 zwei (16-Bit-Offset) weiter
+ rts
+S_pc_idx:
+ move.l a0,a1 ; PC nach A1
+ clr.w d2 ; Oberes Byte loeschen
+ move.b 5(a0),d2 ; Offset nach D2
+ adda.w d2,a1 ; und addieren
+ addq.l #4,a1 ; +4 fuer Laenge 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 S_pc_i_l ; <>0 -->Long-Index
+ and.b #%11110000,d2 ; Registerinformation 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 (8-Bit-Offset & Kram) weiter
+ rts
+S_pc_i_l:
+ and.b #%11110000,d2 ; Restinformation ausblenden
+ lsr.w #2,d2 ; D2=Registernummer*4 (und Modusbit)
+ adda.l 0(a3,d2.w),a1 ; Long-Index addieren
+ addq.l #2,a0 ; A0 zwei (8-Bit-Offset & Kram) weiter
+ rts ; Ende von S_calc_add
+
+S_cs_tab:
+ dc.l S_c_drd,S_c_ard,S_c_ari,S_c_arpo ; Sprungtabelle fuer
+ dc.l S_c_arpr,S_c_ar16,S_c_ar08,S_c_pc ; Adressierungsarten
+S_End:
+
diff --git a/tests/t_parsys/t_parsys.doc b/tests/t_parsys/t_parsys.doc
new file mode 100644
index 0000000..10d31c7
--- /dev/null
+++ b/tests/t_parsys/t_parsys.doc
@@ -0,0 +1,8 @@
++---------------------- Test Application PARSYS ----------------------------+
+| |
+| Back to the roots! This is the "operating system" of my 68000-based par- |
+| allel computer I built several years ago and which was the main reason to |
+| write my own assembler because the original one from RDK was too buggy to |
+| work reliably with it. Contains also a lot of FPU orders. |
+| |
++----------------------------------------------------------------------------+
diff --git a/tests/t_parsys/t_parsys.inc b/tests/t_parsys/t_parsys.inc
new file mode 100644
index 0000000..7ffd805
--- /dev/null
+++ b/tests/t_parsys/t_parsys.inc
@@ -0,0 +1,10 @@
+(* tests/t_parsys/t_parsys.asm-Includefile für CONST-Sektion *)
+S_RegSave = $608;
+S_MemEnd = $400;
+S_ParNo = $408;
+S_CPUNo = $422;
+_fadd_cnt = $40E;
+_fmul_cnt = $412;
+_fdiv_cnt = $416;
+_fsqrt_cnt = $41A;
+(* Ende Includefile für CONST-Sektion *)
diff --git a/tests/t_parsys/t_parsys.ori b/tests/t_parsys/t_parsys.ori
new file mode 100644
index 0000000..d26be99
--- /dev/null
+++ b/tests/t_parsys/t_parsys.ori
Binary files differ