2
This file is part of the Free Pascal run time library.
3
Copyright (c) 1999-2000 by Carl-Eric Codere,
4
member of the Free Pascal development team
6
See the file COPYING.FPC, included in this distribution,
7
for details about the copyright.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
**********************************************************************}
14
{*************************************************************************}
16
{ Ported to FPC-Pascal by Carl Eric Codere }
17
{ Terms of use: This source code is freeware. }
18
{*************************************************************************}
19
{ This inc. implements low-level mathemtical routines for the motorola }
20
{ 68000 family of processors. }
21
{*************************************************************************}
22
{ single floating point routines taken from GCC 2.5.2 Atari compiler }
25
{ written by Kai-Uwe Bloem (I5110401@dbstu1.bitnet). }
26
{ Based on a 80x86 floating point packet from comp.os.minix, }
27
{ written by P.Housel }
28
{ Patched by Olaf Flebbe (flebbe@tat.physik.uni-tuebingen.de) }
29
{ Revision by michal 05-93 (ntomczak@vm.ucs.ualberta.ca) }
30
{*************************************************************************}
31
{--------------------------------------------------------------------}
33
{ o Add support for FPU if present. }
34
{ o Verify if single comparison works in all cases. }
35
{ o Add support for NANs in SINGLE_CMP }
36
{ o Add comp (80-bit) multiplication,addition,substract,division, }
38
{ o Add stack checking for the routines which use the stack. }
39
{ (This will probably have to be done in the code generator). }
40
{--------------------------------------------------------------------}
44
Procedure Single_Norm;[alias : 'FPC_SINGLE_NORM'];Assembler;
45
{--------------------------------------------}
46
{ Low-level routine to normalize single e }
47
{ IEEE floating point values. Never called }
51
{ Registers destroyed: d0,d1 }
52
{--------------------------------------------}
54
tst.l d4 { rounding and u.mant == 0 ? }
59
clr.b d2 { "sticky byte" }
63
tst.w d0 { divide (shift) }
64
ble @normlab2 { denormalized number }
66
and.l d5,d3 { or until no bits above 23 }
69
addq.w #1,d0 { increment exponent }
71
or.b d1,d2 { set "sticky" }
72
roxr.b #1,d1 { shift into rounding bits }
76
or.b d2,d1 { make least sig bit "sticky" }
77
asr.l #1,d5 { #0xff800000 -> d5 }
79
move.l d4,d3 { multiply (shift) until }
80
and.l d5,d3 { one in "implied" position }
82
subq.w #1,d0 { decrement exponent }
83
beq @normlab7 { too small. store as denormalized number }
84
add.b d1,d1 { some doubt about this one * }
88
tst.b d1 { check rounding bits }
89
bge @normlab9 { round down - no action neccessary }
91
bvc @normlab8 { round up }
92
move.w d4,d1 { tie case - round to even }
93
{ dont need rounding bits any more }
94
and.w #1,d1 { check if even }
95
beq @normlab9 { mantissa is even - no action necessary }
98
clr.w d1 { zero rounding bits }
101
bne @normlab10 { renormalize if number was denormalized }
102
add.w #1,d0 { correct exponent for denormalized numbers }
105
move.l d4,d3 { check for rounding overflow }
106
asl.l #1,d5 { #0xff000000 -> d5 }
108
bne @normlab4 { go back and renormalize }
110
tst.l d4 { check if normalization caused an underflow }
112
tst.w d0 { check for exponent overflow or underflow }
117
lsl.w #8,d0 { re-position exponent - one bit too high }
118
lsl.w #1,d2 { get X bit }
119
roxr.w #1,d0 { shift it into sign position }
120
swap d0 { map to upper word }
122
and.l #$7fffff,d4 { top mantissa bits }
123
or.l d4,d0 { insert exponent and sign }
128
{ handling underflow should be done here... }
129
{ by default simply return 0 as retzok... }
133
roxr.l #1,d0 { sign of 0 is the same as of d2 }
138
move.l #$7f800000,d0 { +infinity as proposed by IEEE }
140
tst.w d2 { transfer sign }
141
bge @ofl_clear { (mjr++) }
144
or.b #2,ccr { set overflow flag. }
150
Procedure Single_AddSub; Assembler;
151
{--------------------------------------------}
152
{ Low-level routine to add/subtract single }
153
{ IEEE floating point values. Never called }
156
{ d0 = result -- from normalize routine }
157
{ Flags : V set if overflow. }
158
{ on underflow d0 = 0 }
159
{ Registers destroyed: d0,d1 }
160
{--------------------------------------------}
162
{--------------------------------------------}
164
{ d1-d0 = single values to subtract. }
165
{--------------------------------------------}
167
eor.l #$80000000,d0 { reverse sign of v }
168
{--------------------------------------------}
170
{ d0, d1 = single values to add. }
171
{--------------------------------------------}
173
movem.l d2-d5,-(sp) { save registers }
174
move.l d0,d4 { d4 = d0 = v }
175
move.l d1,d5 { d5 = d1 = u }
178
move.l d5,d0 { d0 = u.exp }
179
move.l d5,d2 { d2.h = u.sign }
181
move.w d0,d2 { d2 = u.sign }
182
and.l d3,d5 { remove exponent from u.mantissa }
184
move.l d4,d1 { d1 = v.exp }
185
and.l d3,d4 { remove exponent from v.mantissa }
187
eor.w d1,d2 { d2 = u.sign ^ v.sign (in bit 15)}
188
clr.b d2 { we will use the lowest byte as a flag }
190
bclr d3,d1 { kill sign bit u.exp }
191
bclr d3,d0 { kill sign bit u.exp }
192
btst d3,d2 { same sign for u and v? }
194
cmp.l d0,d1 { different signs - maybe x - x ? }
195
seq d2 { set 'cancellation' flag }
197
lsr.w #7,d0 { keep here exponents only }
199
{--------------------------------------------------------------------}
200
{ Now perform testing of NaN and infinities }
201
{--------------------------------------------------------------------}
208
{--------------------------------------------------------------------}
210
{--------------------------------------------------------------------}
213
bne @retnan { cancellation of specials -> NaN }
215
bne @retnan { arith with Nan gives always NaN }
217
addq.w #4,a0 { here is an infinity }
219
bne @alabel3 { skip check for NaN if v not special }
220
{--------------------------------------------------------------------}
222
{--------------------------------------------------------------------}
229
{--------------------------------------------------------------------}
230
{ Return a quiet nan }
231
{--------------------------------------------------------------------}
234
lsr.l #1,d0 { 0x7fffffff -> d0 }
236
{ Ok, no inifinty or NaN involved.. }
240
moveq.l #0,d0 { x - x hence we always return +0 }
247
bset d3,d5 { restore implied leading "1" }
248
tst.w d0 { check for zero exponent - no leading "1" }
250
bclr d3,d5 { remove it }
251
addq.w #1,d0 { "normalize" exponent }
253
bset d3,d4 { restore implied leading "1" }
254
tst.w d1 { check for zero exponent - no leading "1" }
256
bclr d3,d4 { remove it }
257
addq.w #1,d1 { "normalize" exponent }
259
moveq.l #0,d3 { (put initial zero rounding bits in d3) }
260
neg.w d1 { d1 = u.exp - v.exp }
262
beq @alabel8 { exponents are equal - no shifting neccessary }
263
bgt @alabel7 { not equal but no exchange neccessary }
264
exg d4,d5 { exchange u and v }
265
sub.w d1,d0 { d0 = u.exp - (u.exp - v.exp) = v.exp }
267
tst.w d2 { d2.h = u.sign ^ (u.sign ^ v.sign) = v.sign }
271
cmp.w #26,d1 { is u so much bigger that v is not }
272
bge @alabel9 { significant ? }
273
{--------------------------------------------------------------------}
274
{ shift mantissa left two digits, to allow cancellation of }
275
{ most significant digit, while gaining an additional digit for }
277
{--------------------------------------------------------------------}
281
subq.w #1,d0 { decrement exponent }
282
subq.w #1,d1 { done shifting altogether ? }
283
dbeq d3,@alabel10 { loop if still can shift u.mant more }
286
cmp.w #16,d1 { see if fast rotate possible }
288
or.w d4,d3 { set rounding bits }
299
lsr.l #1,d4 { shift v.mant right the rest of the way }
301
dbra d1,@alabel12 { loop }
304
tst.w d2 { are the signs equal ? }
305
bpl @alabel13 { yes, no negate necessary }
308
tst.w d3 { negate rounding bits and v.mant }
315
add.l d4,d5 { u.mant = u.mant + v.mant }
316
bcs @alabel9 { needn not negate }
317
tst.w d2 { opposite signs ? }
318
bpl @alabel9 { do not need to negate result }
321
not.l d2 { switch sign }
323
move.l d5,d4 { move result for normalization }
329
swap d2 { put sign into d2 (exponent is in d0) }
330
jmp FPC_SINGLE_NORM { leave registers on stack for norm_sf }
334
Procedure Single_Mul;Assembler;
335
{--------------------------------------------}
336
{ Low-level routine to multiply two single }
337
{ IEEE floating point values. Never called }
340
{ d0,d1 = values to multiply }
343
{ Registers destroyed: d0,d1 }
344
{ stack space used (and restored): 8 bytes. }
345
{--------------------------------------------}
349
move.l d0,d4 { d4 = v }
350
move.l d1,d5 { d5 = u }
353
move.l d5,d0 { d0 = u.exp }
354
and.l d3,d5 { remove exponent from u.mantissa }
356
move.w d0,d2 { d2 = u.sign }
358
move.l d4,d1 { d1 = v.exp }
359
and.l d3,d4 { remove exponent from v.mantissa }
361
eor.w d1,d2 { d2 = u.sign ^ v.sign (in bit 15)}
364
bclr d3,d0 { kill sign bit }
365
bclr d3,d1 { kill sign bit }
366
tst.l d0 { test if one of factors is 0 }
370
seq d2 { 'one of factors is 0' flag in the lowest byte }
371
lsr.w #7,d0 { keep here exponents only }
374
{--------------------------------------------------------------------}
375
{ Now perform testing of NaN and infinities }
376
{--------------------------------------------------------------------}
383
{--------------------------------------------------------------------}
384
{ first operand is special }
385
{--------------------------------------------------------------------}
387
tst.l d5 { is it NaN? }
390
tst.b d2 { 0 times special or special times 0 ? }
391
bne @mretnan { yes -> NaN }
392
cmp.b d3,d1 { is the other special ? }
393
beq @mlabel4 { maybe it is NaN }
394
{--------------------------------------------------------------------}
395
{ Return infiny with correct sign }
396
{--------------------------------------------------------------------}
398
move.l #$ff000000,d0 { we will return #0xff800000 or #0x7f800000 }
400
roxr.l #1,d0 { shift in high bit as given by d2 }
405
{--------------------------------------------------------------------}
407
{--------------------------------------------------------------------}
409
tst.l d4 { is this NaN? }
410
beq @mretinf { we know that the other is not zero }
413
lsr.l #1,d0 { 0x7fffffff -> d0 }
415
{--------------------------------------------------------------------}
416
{ End of NaN and Inf }
417
{--------------------------------------------------------------------}
419
tst.b d2 { not needed - but we can waste two instr. }
420
bne @mretzz { return signed 0 if one of factors is 0 }
422
bset d3,d5 { restore implied leading "1" }
423
subq.w #8,sp { multiplication accumulator }
424
tst.w d0 { check for zero exponent - no leading "1" }
426
bclr d3,d5 { remove it }
427
addq.w #1,d0 { "normalize" exponent }
430
beq @mretz { multiplying zero }
433
bset d3,d4 { restore implied leading "1" }
434
tst.w d1 { check for zero exponent - no leading "1" }
436
bclr d3,d4 { remove it }
437
addq.w #1,d1 { "normalize" exponent }
440
beq @mretz { multiply by zero }
442
add.w d1,d0 { add exponents, }
443
sub.w #BIAS4+16-8,d0 { remove excess bias, acnt for repositioning }
445
clr.l (sp) { initialize 64-bit product to zero }
447
{--------------------------------------------------------------------}
448
{ see Knuth, Seminumerical Algorithms, section 4.3. algorithm M }
449
{--------------------------------------------------------------------}
451
mulu.w d5,d3 { mulitply with bigit from multiplier }
452
move.l d3,4(sp) { store into result }
457
add.l d3,2(sp) { add to result }
459
swap d5 { [TOP 8 BITS SHOULD BE ZERO !] }
462
mulu.w d5,d3 { mulitply with bigit from multiplier }
463
add.l d3,2(sp) { store into result (no carry can occur here) }
468
add.l d3,(sp) { add to result }
469
{ [TOP 16 BITS SHOULD BE ZERO !] }
470
movem.l 2(sp),d4-d5 { get the 48 valid mantissa bits }
471
clr.w d5 { (pad to 64) }
475
cmp.l d3,d4 { multiply (shift) until }
476
bhi @mlabel8 { 1 in upper 16 result bits }
477
cmp.w #9,d0 { give up for denormalized numbers }
479
swap d4 { (we''re getting here only when multiplying }
480
swap d5 { with a denormalized number; there''s an }
481
move.w d5,d4 { eventual loss of 4 bits in the rounding }
482
clr.w d5 { byte -- what a pity 8-) }
483
subq.w #8,d0 { decrement exponent }
487
move.l d5,d1 { get rounding bits }
489
move.l d1,d3 { see if sticky bit should be set }
492
or.b #1,d1 { set "sticky bit" if any low-order set }
494
addq.w #8,sp { remove accumulator from stack }
495
jmp FPC_SINGLE_NORM{ (result in d4) }
498
addq.w #8,sp { release accumulator space }
500
moveq.l #0,d0 { save zero as result }
501
lsl.w #1,d2 { and set it sign as for d2 }
504
rts { no normalizing neccessary }
508
Procedure Single_Div;Assembler;
509
{--------------------------------------------}
510
{ Low-level routine to dividr two single }
511
{ IEEE floating point values. Never called }
514
{ d1/d0 = u/v = operation to perform. }
517
{ Registers destroyed: d0,d1 }
518
{ stack space used (and restored): 8 bytes. }
519
{--------------------------------------------}
522
{ u = d1 = dividend }
524
tst.l d0 { check if divisor is 0 }
528
btst #31,d1 { transfer sign of dividend }
535
move.l d1,d4 { d4 = u, d5 = v }
537
movem.l d2-d5,-(sp) { save registers }
540
move.l d4,d0 { d0 = u.exp }
541
and.l d3,d4 { remove exponent from u.mantissa }
543
move.w d0,d2 { d2 = u.sign }
545
move.l d5,d1 { d1 = v.exp }
546
and.l d3,d5 { remove exponent from v.mantissa }
548
eor.w d1,d2 { d2 = u.sign ^ v.sign (in bit 15) }
551
bclr d3,d0 { kill sign bit }
552
bclr d3,d1 { kill sign bit }
557
cmp.b d3,d0 { comparison with #0xff }
558
beq @dlabel1 { u == NaN ;; u== Inf }
560
beq @dlabel2 { v == NaN ;; v == Inf }
562
bne @dlabel4 { u not zero nor denorm }
564
beq @dlabel3 { 0/ ? }
572
bra @dretinf { x/0 -> +/- Inf }
575
tst.l d4 { u == NaN ? }
576
bne @dretnan { NaN/ x }
578
beq @dretnan { Inf/Inf or Inf/NaN }
579
{ bra dretinf ; Inf/x ; x != Inf && x != NaN }
580
{--------------------------------------------------------------------}
581
{ Return infinity with correct sign. }
582
{--------------------------------------------------------------------}
586
roxr.l #1,d0 { shift in high bit as given by d2 }
593
bne @dretnan { x/NaN }
594
{ bra dretzero ; x/Inf -> +/- 0 }
595
{--------------------------------------------------------------------}
596
{ Return correct signed zero. }
597
{--------------------------------------------------------------------}
599
moveq.l #0,d0 { zero destination }
600
lsl.w #1,d2 { set X bit accordingly }
606
bne @dretzero { 0/x ->+/- 0 }
608
bne @dretzero { 0/x }
610
{--------------------------------------------------------------------}
611
{ Return NotANumber }
612
{--------------------------------------------------------------------}
614
move.l d3,d0 { d3 contains 0xffffffff }
617
{--------------------------------------------------------------------}
618
{ End of Special Handling }
619
{--------------------------------------------------------------------}
622
bset d3,d4 { restore implied leading "1" }
623
tst.w d0 { check for zero exponent - no leading "1" }
625
bclr d3,d4 { remove it }
626
add.w #1,d0 { "normalize" exponent }
629
beq @dretzero { dividing zero }
631
bset d3,d5 { restore implied leading "1" }
632
tst.w d1 { check for zero exponent - no leading "1"}
634
bclr d3,d5 { remove it }
635
add.w #1,d1 { "normalize" exponent }
638
sub.w d1,d0 { subtract exponents, }
639
add.w #BIAS4-8+1,d0 { add bias back in, account for shift }
640
add.w #34,d0 { add loop offset, +2 for extra rounding bits}
641
{ for denormalized numbers (2 implied by dbra)}
642
move.w #27,d1 { bit number for "implied" pos (+4 for rounding)}
643
moveq.l #-1,d3 { zero quotient (for speed a one''s complement) }
644
sub.l d5,d4 { initial subtraction, u = u - v }
646
btst d1,d3 { divide until 1 in implied position }
650
bcs @dlabel8 { if carry is set, add, else subtract }
652
addx.l d3,d3 { shift quotient and set bit zero }
653
sub.l d5,d4 { subtract, u = u - v }
654
dbra d0,@dlabel7 { give up if result is denormalized }
657
addx.l d3,d3 { shift quotient and clear bit zero }
658
add.l d5,d4 { add (restore), u = u + v }
659
dbra d0,@dlabel7 { give up if result is denormalized }
661
subq.w #2,d0 { remove rounding offset for denormalized nums }
662
not.l d3 { invert quotient to get it right }
664
clr.l d1 { zero rounding bits }
665
tst.l d4 { check for exact result }
667
moveq.l #-1,d1 { prevent tie case }
669
move.l d3,d4 { save quotient mantissa }
670
jmp FPC_SINGLE_NORM{ (registers on stack removed by norm_sf) }
674
Procedure Single_Cmp; Assembler;
675
{--------------------------------------------}
676
{ Low-level routine to compare single two }
677
{ single point values.. }
678
{ Never called directly. }
680
{ d1 and d0 Values to compare }
681
{ d0 = first operand }
683
{ Flags according to result }
684
{ Registers destroyed: d0,d1 }
685
{--------------------------------------------}
688
tst.l d0 { check sign bit }
691
bchg #31,d0 { toggle sign bit }
693
tst.l d1 { check sign bit }
696
bchg #31,d1 { toggle sign bit }
698
cmp.l d0,d1 { compare... }
704
Procedure LongMul;Assembler;
705
{--------------------------------------------}
706
{ Low-level routine to multiply two signed }
707
{ 32-bit values. Never called directly. }
708
{ On entry: d1,d0 = 32-bit signed values to }
712
{ Registers destroyed: d0,d1 }
713
{ stack space used and restored: 10 bytes }
714
{--------------------------------------------}
717
cmp.b #2,Test68000 { Are we on a 68020+ cpu }
719
muls.l d1,d0 { yes, then directly mul... }
720
rts { return... result in d0 }
722
move.l d2,a0 { save registers }
728
movem.w (sp)+,d0-d3 { u = d0-d1, v = d2-d3 }
730
move.w d0,-(sp) { sign flag }
731
bpl @LMul1 { is u negative ? }
732
neg.w d1 { yes, force it positive }
735
tst.w d2 { is v negative ? }
737
neg.w d3 { yes, force it positive ... }
739
not.w (sp) { ... and modify flag word }
741
ext.l d0 { u.h <> 0 ? }
743
mulu.w d3,d0 { r = v.l * u.h }
745
tst.w d2 { v.h <> 0 ? }
747
mulu.w d1,d2 { r += v.h * u.l }
752
mulu.w d3,d1 { r += v.l * u.l }
756
tst.w (sp)+ { should the result be negated ? }
757
bpl @LMul5 { no, just return }
758
neg.l d0 { else r = -r }
765
Procedure Long2Single;Assembler;
766
{--------------------------------------------}
767
{ Low-level routine to convert a longint }
768
{ to a single floating point value. }
769
{ On entry: d0 = longint value to convert. }
771
{ d0 = single IEEE value }
772
{ Registers destroyed: d0,d1 }
773
{ stack space used and restored: 8 bytes }
774
{--------------------------------------------}
777
movem.l d2-d5,-(sp) { save registers to make norm_sf happy}
779
move.l d0,d4 { prepare result mantissa }
780
move.w #BIAS4+32-8,d0 { radix point after 32 bits }
781
move.l d4,d2 { set sign flag }
782
bge @l2slabel1 { nonnegative }
783
neg.l d4 { take absolute value }
785
swap d2 { follow SINGLE_NORM conventions }
786
clr.w d1 { set rounding = 0 }
791
Procedure LongDiv; [alias : 'FPC_LONGDIV'];Assembler;
792
{--------------------------------------------}
793
{ Low-level routine to do signed long }
795
{ On entry: d0/d1 operation to perform }
799
{ Registers destroyed: d0,d1,d6 }
800
{ stack space used and restored: 10 bytes }
801
{--------------------------------------------}
804
cmp.b #2,Test68000 { can we use divs ? }
810
tst.l d0 { check sign of d0 }
812
move.l #$ffffffff,d1{ sign extend into d1 }
818
move.l d2,a0 { save registers }
820
move.l d4,-(sp) { divisor = d1 = d4 }
821
move.l d5,-(sp) { divident = d0 = d5 }
823
move.l d1,d4 { save divisor }
824
move.l d0,d5 { save dividend }
826
clr.w -(sp) { sign flag }
828
clr.l d0 { prepare result }
829
move.l d4,d2 { get divisor }
830
beq @zerodiv { divisor = 0 ? }
831
bpl @LDiv1 { divisor < 0 ? }
832
neg.l d2 { negate it }
833
not.w (sp) { remember sign }
835
move.l d5,d1 { get dividend }
836
bpl @LDiv2 { dividend < 0 ? }
837
neg.l d1 { negate it }
838
not.w (sp) { remember sign }
840
{;== case 1) divident < divisor}
841
cmp.l d2,d1 { is divident smaller then divisor ? }
842
bcs @LDiv7 { yes, return immediately }
843
{;== case 2) divisor has <= 16 significant bits}
844
move.l d4,d6 { put divisor in d6 register }
845
lsr.l #8,d6 { rotate into low word }
848
bne @LDiv3 { divisor has only 16 bits }
849
move.w d1,d3 { save dividend }
850
clr.w d1 { divide dvd.h by dvs }
852
beq @LDiv4 { (no division necessary if dividend zero)}
855
move.w d1,d0 { save quotient.h }
857
move.w d3,d1 { (d0.h = remainder of prev divu) }
858
divu d2,d1 { divide dvd.l by dvs }
859
move.w d1,d0 { save quotient.l }
860
clr.w d1 { get remainder }
862
bra @LDiv7 { and return }
863
{;== case 3) divisor > 16 bits (corollary is dividend > 16 bits, see case 1)}
865
moveq.l #31,d3 { loop count }
867
add.l d1,d1 { shift divident ... }
868
addx.l d0,d0 { ... into d0 }
869
cmp.l d2,d0 { compare with divisor }
871
sub.l d2,d0 { big enough, subtract }
872
addq.w #1,d1 { and note bit into result }
875
exg d0,d1 { put quotient and remainder in their registers}
877
tst.l d5 { must the remainder be corrected ? }
879
neg.l d1 { yes, apply sign }
880
{ the following line would be correct if modulus is defined as in algebra}
881
{; add.l sp@(6),d1 ; algebraic correction: modulus can only be >= 0}
883
tst.w (sp)+ { result should be negative ? }
885
neg.l d0 { yes, negate it }
891
rts { en exit : remainder = d1, quotient = d0 }
893
move.l a1,d3 { restore stack... }
895
move.w (sp)+,d1 { remove sign word }
900
jsr FPC_HALT_ERROR { RunError(200) }
901
rts { this should never occur... }
905
Procedure LongMod;[alias : 'FPC_LONGMOD'];Assembler;
906
{ see longdiv for info on calling convention }
910
move.l d1,d0 { return the remainder in d0 }