DragonFPImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last edited by Curry, February 8, 1985 2:02:15 pm PST
DIRECTORY
Basics,
BitOps,
Dragon,
DragonFP,
IO;
DragonFPImpl: CEDAR PROGRAM
IMPORTS Basics, BitOps, Dragon, IO
EXPORTS DragonFP =
BEGIN OPEN DragonFP;
SetMode: PUBLIC PROC[mode: Mode, function: Function] RETURNS[Mode] = {
word: BitOps.BitWord ← LOOPHOLE[mode];
word ← BitOps.ICIW[function MOD 16, word,16, ((function MOD 64)/16)*4, 4];
RETURN[ LOOPHOLE[word]] };
ALU: PUBLIC PROC  [aHDW, bHDW: HexDblWord, func: Function, mode: Mode]
RETURNS [cHDW: HexDblWord, status: Dragon.PBusFaults] = {
resDbl: BOOL ← func MOD 2 = 1;
Dragon.Assert[mode.required = requiredMode];
funcfunc MOD 64;
SELECT func/2 FROM
IN [0..24) => {
aFP,bFP:FP;
aFP ← HDWtoFP[aHDW];
bFP ← HDWtoFP[bHDW];
IF (func MOD 8) IN [6..7]
THEN {
IF (func/8) MOD 2 =1 THEN aFP.exp ← aFP.exp - WrapBias[aFP];
IF (func/16) MOD 2 =1 THEN bFP.exp ← bFP.exp - WrapBias[bFP];
[cHDW, status] ← FDiv[aFP, bFP, resDbl, mode]}
ELSE {
IF (func MOD 16) >7 THEN bFP   ← HDWtoFP[[0,0,FALSE]];
IF (func MOD 8)/2=2 THEN aFP.sign ← bFP.sign ← FALSE;
IF func/2 = 4    THEN aFP.sign ← NOT aFP.sign;
IF func  < 6    THEN bFP.sign ← NOT bFP.sign;
IF func  <32
THEN [cHDW, status] ← FAdd[aFP, bFP, resDbl, mode]
ELSE [cHDW, status] ← FCmp[aFP, bFP, resDbl, mode]} };
24 => [cHDW, status] ← UtoD [aHDW, mode, TRUE];
25 => [cHDW, status] ← DtoW [aHDW, mode];
26 => [cHDW, status] ← UtoD [aHDW, mode, FALSE];
28 => [cHDW, status] ← FtoI [aHDW, mode];
29 => [cHDW, status] ← ItoF [aHDW, mode, resDbl];
30 => [cHDW, status] ← FtoF [aHDW, mode, resDbl];
ENDCASE => Dragon.Assert[FALSE, "Strange FP Function"];
RETURN[cHDW, status]};
MUL: PUBLIC PROC [aHDW,bHDW: HexDblWord, function: Function, mode: Mode]
RETURNS [cHDW: HexDblWord, status: Dragon.PBusFaults] = {
acc: ARRAY[0..8) OF CARDINALALL[0];
resDbl:  BOOL ← (function MOD 2)/1  = 1;
aWraped:  BOOL ← (function MOD 4)/2  = 1;
bWraped:  BOOL ← (function MOD 8)/4  = 1;
aMagnitude: BOOL ← (function MOD 16)/8  = 1;
bMagnitude: BOOL ← (function MOD 32)/16 = 1;
compResult: BOOL ← (function MOD 64)/32 = 1;
a:    FP  ← HDWtoFP[aHDW];
b:    FP  ← HDWtoFP[bHDW];
Dragon.Assert[mode.required = requiredMode];
IF (function MOD 8)/2 = 2 THEN a.sign ← b.sign ← FALSE;
IF (function MOD 64)/2 = 4 THEN a.sign ← TRUE;
IF (function MOD 64) >=32  THEN b.sign ← NOT b.sign;
IF compResult     THEN a.sign ← NOT a.sign;
IF a.type = nan AND b.type = nan THEN    RETURN[FPtoHDW[a], FPabNaN];
IF a.type = nan       THEN    RETURN[FPtoHDW[a], FPaNaN];
IF       b.type = nan THEN    RETURN[FPtoHDW[b], FPaNaN];
IF a.double AND NOT resDbl   THEN    RETURN[FPtoHDW[a], FPinvalid];
IF b.double AND NOT resDbl   THEN    RETURN[FPtoHDW[b], FPinvalid];
IF a.exp<MinExp[a] AND mode.fast THEN SetToZero[a];
IF b.exp<MinExp[b] AND mode.fast THEN SetToZero[b];
IF a.type = zero AND b.type = inf OR
b.type = zero AND a.type = inf THEN{a.type←nan;  RETURN[FPtoHDW[a], FPinvalid]};
IF a.type = inf  THEN {a.sign ← a.sign#b.sign; RETURN[FPtoHDW[a], FPlsInfE]};
IF b.type = inf  THEN {b.sign ← a.sign#b.sign; RETURN[FPtoHDW[b], FPlsInfE]};
IF b.type = zero  THEN {b.sign ← a.sign#b.sign; RETURN[FPtoHDW[b], FPeqZeroE]};
IF a.type = zero  THEN {a.sign ← a.sign#b.sign; RETURN[FPtoHDW[a], FPeqZeroE]};
IF a.exp<MinExp[a] AND b.exp<MinExp[b] THEN  RETURN[FPtoHDW[a], FPabDeNorm];
IF a.exp<MinExp[a]        THEN  RETURN[FPtoHDW[a], FPaDeNorm];
IF        b.exp<MinExp[b] THEN  RETURN[FPtoHDW[b], FPbDeNorm];
a and b are normal and non-zero
IF aWraped THEN a.exp ← a.exp - WrapBias[a];
IF bWraped THEN a.exp ← a.exp - WrapBias[b];
a.exp ← a.exp - FPExpBias + b.exp +1;
a.sign ← a.sign # b.sign;
FOR i: CARDINAL DECREASING IN [0..4) DO -- acc[1-7] ← a*b, acc[0] ← carry
cy:CARDINAL ← 0;
FOR j: CARDINAL DECREASING IN [0..4) DO
long:Basics.LongNumber;
long.lc ← Basics.LongMult[a.m[i], b.m[j]];
[cy, acc[i+j+1]] ← ADC3[long.lowbits, acc[i+j+1], cy];
cy ← cy + long.highbits;
ENDLOOP;
FOR j: CARDINAL DECREASING IN [0..i] WHILE cy#0
DO [cy, acc[j]] ← ADC3[acc[j], cy, 0]
ENDLOOP;
ENDLOOP;
WHILE acc[0] < 100000B DO
a.exp ← a.exp - 1;
FOR i:CARDINAL IN [0..7) DO
acc[i] ← acc[i]*2;
IF acc[i+1] > 100000B THEN acc[i] ← acc[i] + 1;
ENDLOOP;
acc[7] ← acc[7]*2
ENDLOOP;
FOR i:CARDINAL IN [0..3] DO a.m[i] ← acc[i] ENDLOOP;
FOR i:CARDINAL DECREASING IN [4..7] WHILE (a.m[3] MOD 2) = 0 DO
IF acc[i]#0 THEN a.m[3] ← a.m[3] +1 ENDLOOP;
status ← RoundMult[a, mode];
RETURN [FPtoHDW[a], status] };
PutHexFP: PUBLIC PROC[st:IO.STREAM, hdw: HexDblWord] = {
fp: FP ← HDWtoFP[hdw];
hexChar: ARRAY [0..16) OF CHARACTER ← ['0,'1,'2,'3,'4,'5,'6,'7,'8,'9,'A,'B,'C,'D,'E,'F];
charVal: ARRAY [0..16) OF CHARACTERALL['0];
nonZeroCnt: CARDINAL ← 0;
val, cy: CARDINAL ← 0;
SELECT fp.type FROM
zero => {IO.PutF[st, IF fp.sign THEN "-0.0" ELSE "+0.0"];  RETURN};
inf => {IO.PutF[st, IF fp.sign THEN "-INF" ELSE "+INF"]; RETURN};
nan => {IO.PutF[st, "NaN"]; RETURN};
ENDCASE;
FOR i:CARDINAL DECREASING IN [0..4) DO
val ← (fp.m[i] MOD 100000B)*2 + cy;
cy ← fp.m[i] / 100000B;
FOR j:CARDINAL DECREASING IN [0..4) DO
charVal[i*4+j] ← hexChar[val MOD 16];
val ← val / 16;
IF charVal[i*4+j] = '0 AND nonZeroCnt=0 THEN LOOP;
nonZeroCnt ← nonZeroCnt+1;
ENDLOOP;
ENDLOOP;
IF fp.sign THEN IO.PutF[st, "-" ];
IO.PutF[st, "1." ];
FOR i:CARDINAL IN [0..MAX[1, nonZeroCnt]) DO st.PutChar[charVal[i]] ENDLOOP;
IF fp.exp # FPExpBias THEN IF fp.exp>FPExpBias
THEN {IO.PutF[st, "e"]; val ← fp.exp-FPExpBias}
ELSE {IO.PutF[st, "e-"]; val ← FPExpBias-fp.exp};
nonZeroCnt ← 0;
FOR div:CARDINAL �, div/16 WHILE div#0 DO
IF (val/div) = 0 AND nonZeroCnt=0 THEN LOOP;
st.PutChar[hexChar[val/div]];
nonZeroCnt ← nonZeroCnt+1;
val ← val MOD div;
ENDLOOP};
Private:
FP: TYPE = REF FPRec;
FPType: TYPE = {norm, zero, den, inf, nan};
FPExpBias: CARDINAL = 16383;
FPRec: TYPE = RECORD [
double: BOOL  ← FALSE,
type:  FPType ← norm,
sign:  BOOL  ← FALSE,
exp:  CARDINAL ← 0,
m:   ARRAY[0..4) OF CARDINALALL[0]];
FDiv: PROC [rem,dvsr: FP, dblRes:BOOL, mode:Mode] RETURNS [c:HexDblWord, status:Dragon.PBusFaults] = {
FPComp: PROC[x, y: FP] RETURNS[comp: {gr,ls,eq}] = {
comp ← eq;
FOR i: CARDINAL IN [0..4) DO
IF x.m[i] = y.m[i] THEN LOOP;
RETURN[IF x.m[i]>y.m[i] THEN gr ELSE ls] ENDLOOP };
q: FP ← HDWtoFP[[0,0,NOT dblRes]];
IF rem.type=nan AND dvsr.type=nan THEN  RETURN[FPtoHDW[rem], FPabNaN];
IF rem.type=nan       THEN  RETURN[FPtoHDW[rem], FPaNaN];
IF dvsr.type=nan      THEN  RETURN[FPtoHDW[dvsr], FPbNaN];
IF rem.double AND NOT dblRes THEN  RETURN[FPtoHDW[rem], FPinvalid];
IF dvsr.double AND NOT dblRes THEN  RETURN[FPtoHDW[dvsr], FPinvalid];
IF dvsr.type=zero      THEN  RETURN[FPtoHDW[dvsr], FPdivByZero];
rem.double ← dvsr.double ← dblRes;
rem.sign ← dvsr.sign ← rem.sign#dvsr.sign;
IF rem.type=zero       THEN  RETURN[FPtoHDW[rem], FPeqZeroE];
IF rem.type=inf AND dvsr.type=inf THEN
 {SetToNaN[rem];        RETURN[FPtoHDW[rem], FPinvalid]};
IF rem.type=inf       THEN  RETURN[FPtoHDW[rem], FPlsInfE] ;
IF dvsr.type=inf       THEN
 {SetToZero[dvsr];        RETURN[FPtoHDW[dvsr], FPeqZeroE]};
q.sign  ← rem.sign; rem.sign ← FALSE; dvsr.sign ← TRUE;
q.exp  ← FPExpBias + 60 + rem.exp - dvsr.exp;
dvsr.exp ← rem.exp;
FOR i: CARDINAL IN [1..60] DO
ShiftLt[q];
SELECT FPComp[rem, dvsr] FROM
gr, eq  => {
cy: CARDINAL ← 1;
[cy, rem.m[3]] ← ADC3[rem.m[3], Basics.BITNOT[dvsr.m[3]], cy];
[cy, rem.m[2]] ← ADC3[rem.m[2], Basics.BITNOT[dvsr.m[2]], cy];
[cy, rem.m[1]] ← ADC3[rem.m[1], Basics.BITNOT[dvsr.m[1]], cy];
[cy, rem.m[0]] ← ADC3[rem.m[0], Basics.BITNOT[dvsr.m[0]], cy];
IF SignificantBitsZero[rem] THEN SetToZero[rem] ELSE Normalize[rem];
q.m[3] ← q.m[3] + 1};
ENDCASE;
dvsr.exp ← dvsr.exp - 1
ENDLOOP;
Normalize[q];
status ← RoundFP[q, mode.rnd];
RETURN [ FPtoHDW[q], status ] };
FAdd: PROC [a, b: FP, dblRes: BOOL, mode: Mode] RETURNS [c: HexDblWord, status: Dragon.PBusFaults] = {
FPComp: PROC[x, y: FP] RETURNS[r: {gr,ls,eq}] = {
r ← eq;
FOR i:CARDINAL IN [0..4) DO
IF x.m[i] = y.m[i] THEN LOOP;
RETURN[IF x.m[i]>y.m[i] THEN gr ELSE ls] ENDLOOP };
IF a.type=nan AND b.type=nan THEN  RETURN[FPtoHDW[a], FPabNaN];
IF a.type=nan       THEN  RETURN[FPtoHDW[a], FPaNaN];
IF b.type=nan      THEN  RETURN[FPtoHDW[b], FPbNaN];
IF a.double AND NOT dblRes THEN  RETURN[FPtoHDW[a], FPinvalid];
IF b.double AND NOT dblRes THEN  RETURN[FPtoHDW[b], FPinvalid];
a.double ← dblRes;
b.double ← dblRes;
IF a.type=inf AND b.type=inf THEN IF a.sign = b.sign
THEN {a.double ← dblRes;      RETURN[FPtoHDW[a], FPlsInfE]}
ELSE {SetToNaN[a];       RETURN[FPtoHDW[a], FPinvalid]};
IF a.type=inf       THEN  RETURN[FPtoHDW[a], FPlsInfE];
IF b.type=inf       THEN  RETURN[FPtoHDW[b], FPlsInfE];
IF a.type=zero AND b.type=zero THEN {
IF a.sign#b.sign THEN a.sign ← (mode.rnd=rm);
             RETURN[FPtoHDW[a], FPeqZeroE]};
IF a.type=zero      THEN  RETURN[FPtoHDW[b], FPgrNEZeroE];
IF b.type=zero      THEN  RETURN[FPtoHDW[a], FPgrNEZeroE];
IF a.exp >= b.exp
THEN DeNormalize[b, a.exp - b.exp]
ELSE {DeNormalize[a, b.exp - a.exp]; a.exp ← b.exp};
IF a.sign = b.sign
THEN {
cy:CARDINAL ← 0;
[cy, a.m[3]] ← ADC3[a.m[3], b.m[3], cy];
[cy, a.m[2]] ← ADC3[a.m[2], b.m[2], cy];
[cy, a.m[1]] ← ADC3[a.m[1], b.m[1], cy];
[cy, a.m[0]] ← ADC3[a.m[0], b.m[0], cy];
IF cy # 0 THEN {DeNormalize[a,1]; a.m[0] ← a.m[0]+ 100000B} }
ELSE {
cy:CARDINAL ← 1;
IF FPComp[a,b]=ls THEN {c:FP ← a; a ← b; b ← c; a.exp ← b.exp};
[cy, a.m[3]] ← ADC3[a.m[3], Basics.BITNOT[b.m[3]], cy];
[cy, a.m[2]] ← ADC3[a.m[2], Basics.BITNOT[b.m[2]], cy];
[cy, a.m[1]] ← ADC3[a.m[1], Basics.BITNOT[b.m[1]], cy];
[cy, a.m[0]] ← ADC3[a.m[0], Basics.BITNOT[b.m[0]], cy];
IF SignificantBitsZero[a]
THEN {a.sign←mode.rnd=rm; SetToZero[a]}
ELSE Normalize[a]};
status ← RoundFP[a, mode.rnd];
RETURN [ FPtoHDW[a], status ] };
FCmp: PROC [a, b: FP, dblRes: BOOL, mode: Mode] RETURNS[c: HexDblWord, status: Dragon.PBusFaults] = {
status ← SELECT TRUE FROM
a.double AND NOT dblRes  => FPinvalid,
b.double AND NOT dblRes  => FPinvalid,
a.type=nan OR b.type=nan  => FPinvalid,
a.type=inf AND b.type=inf  =>
(IF a.sign=b.sign THEN FPeqZeroE ELSE (IF a.sign THEN FPlsInfE ELSE FPgrNEZeroE)),
a.type=zero AND b.type=zero  => FPeqZeroE,
a.type=zero OR b.type=inf  => IF b.sign THEN FPgrNEZeroE ELSE FPlsInfE,
b.type=zero OR a.type=inf  => IF a.sign THEN FPlsInfE ELSE FPgrNEZeroE,
a.sign#b.sign     => IF a.sign THEN FPlsInfE ELSE FPgrNEZeroE,
ENDCASE       => FPres4;
IF status # FPres4 THEN RETURN[[0, 0, NOT dblRes], status];
a.double ← b.double ← dblRes;
IF a.exp#b.exp
THEN RETURN[[0, 0, NOT dblRes], (IF ((a.exp>b.exp)=a.sign) THEN FPlsInfE ELSE FPgrNEZeroE)];
FOR i:CARDINAL IN [0..3] DO
IF a.m[i]=b.m[i] THEN LOOP;
RETURN[[0, 0, NOT dblRes], (IF ((a.m[i]>b.m[i])=a.sign) THEN FPlsInfE ELSE FPgrNEZeroE)];
ENDLOOP;
RETURN[[0, 0, NOT dblRes], FPeqZeroE] };
UtoD: PROC [a: HexDblWord, mode: Mode, exact: BOOL]
RETURNS [c: HexDblWord, status: Dragon.PBusFaults] = {
fp: FP ← HDWtoFP[a];
IF fp.type#norm THEN
{Dragon.Assert[FALSE, "Undefined"]; RETURN[[0, 0, a.single], FPinvalid]};
fp.exp ← fp.exp - WrapBias[fp];
IF fp.exp >= MinExp[fp] THEN
{Dragon.Assert[FALSE, "Undefined"]; RETURN[[0, 0, a.single], FPinvalid]};
status ← RoundFP[fp, mode.rnd];
RETURN[FPtoHDW[fp], status] };
DtoW: PROC [a: HexDblWord, mode: Mode]
RETURNS [c: HexDblWord, status: Dragon.PBusFaults] = {
fp:  FP ← HDWtoFP[a];
IF fp.type#den THEN
{Dragon.Assert[FALSE, "Undefined"]; RETURN[[0, 0, a.single], FPinvalid]};
fp.exp ← fp.exp + WrapBias[fp];
status ← RoundFP[fp, mode.rnd];
RETURN[FPtoHDW[fp], status] };
FtoI: PROC [a: HexDblWord, mode: Mode] -- Always returns I32
RETURNS [c: HexDblWord, status: Dragon.PBusFaults] = {
minInt: HexDblWord = [20000000000B, 0, FALSE];
maxInt: HexDblWord = [17777777777B, 0, FALSE];
long: Basics.LongNumber;
fp: FP ← HDWtoFP[a];
rnd: FPRndMode ← IF mode.fixRZ THEN rz ELSE mode.rnd;
exact: BOOL;
SELECT fp.type FROM
zero  => RETURN[ [0, 0, FALSE], FPeqZeroE];
nan, inf => IF fp.sign
THENRETURN[minInt, FPoFlowI]
ELSERETURN[maxInt, FPoFlowI];
ENDCASE  => { };
DeNormalize[fp, FPExpBias+64-3-fp.exp]; -- rs on right
exact ← Fix[fp, rnd];
fp.m[3] ← Basics.BITAND[fp.m[3], 177774B]; -- Clear RS
ShiftRt[fp, 2];
IF exact THEN status𡤏PgrNEZeroE ELSE status𡤏PneZeroI;
IF fp.m[0]#0 OR fp.m[1]#0 OR fp.m[2]>=100000B THEN IF fp.sign
THENRETURN[ minInt, FPoFlowI]
ELSERETURN[ maxInt, FPoFlowI];
IF fp.m[2]=0 AND fp.m[3]=0
THEN RETURN[ [0, 0, FALSE], (IF exact THEN FPeqZeroE ELSE FPuFlowI)];
long.highbits ← fp.m[2]; long.lowbits ← fp.m[3];
IF fp.sign THEN long.li ← -long.li;
RETURN[[long.lc, 0, FALSE], status] };
ItoF: PROC [a: HexDblWord, mode: Mode, resDbl: BOOL]
RETURNS [c: HexDblWord, status: Dragon.PBusFaults] = {
long: Basics.LongNumber;
fp: FPNEW[FPRec ← []];
long.lc ← a.h;
IF long.lc = 0 THEN RETURN[ [0,0,NOT resDbl], FPeqZeroE];
fp.sign ← long.li < 0;
IF fp.sign THEN long.li ← -long.li;
fp.m[1] ← long.lowbits;
fp.m[0] ← long.highbits;
fp.exp ← FPExpBias + 31;
fp.double ← resDbl;
Normalize[fp];
status ← RoundFP[fp, mode.rnd];
RETURN[FPtoHDW[fp], status] };
FtoF: PROC [a: HexDblWord, mode: Mode, resDbl: BOOL]
RETURNS [c: HexDblWord, status: Dragon.PBusFaults] = {
fp: FP ← HDWtoFP[a];
fp.double ← resDbl;
status ← RoundFP[fp, mode.rnd];
RETURN[FPtoHDW[fp], status] };
HDWtoFP: PROC[hdw: HexDblWord] RETURNS[fp: FP] = {
lo: BitOps.BitDWord ← Dragon.LTD[hdw.l];
hi: BitOps.BitDWord ← Dragon.LTD[hdw.h];
bitsZero: BOOL;
fp ← NEW[FPRec ← []];
fp.double ← NOT hdw.single;
IF fp.double
THEN {
fp.sign ← BitOps.EBFD[hi, 32, 0];
fp.exp  ← BitOps.ECFD[hi, 32, 1, 11] + MinExp[fp] -1;
fp.m[0] ← BitOps.ECFD[hi, 32, 12, 16];
fp.m[1] ← BitOps.ECFD[hi, 32, 28, 4]*4096 + BitOps.ECFD[lo, 32, 0, 12];
fp.m[2] ← BitOps.ECFD[lo, 32, 12, 16];
fp.m[3] ← BitOps.ECFD[lo, 32, 28, 4]*4096 }
ELSE {
fp.sign ← BitOps.EBFD[hi, 32, 0];
fp.exp  ← BitOps.ECFD[hi, 32, 1, 8] + MinExp[fp]-1;
fp.m[0] ← BitOps.ECFD[hi, 32, 9, 16];
fp.m[1] ← BitOps.ECFD[hi, 32, 25, 7]*512 };
bitsZero ← TRUE;
FOR i:CARDINAL IN [0..3] DO IF fp.m[i]#0 THEN bitsZero ← FALSE ENDLOOP;
SELECT TRUE FROM
fp.exp > MaxExp[fp] AND   bitsZero => {fp.type ← inf; fp.exp ← 32585};
fp.exp > MaxExp[fp] AND NOT bitsZero => {fp.type ← nan; fp.exp ← 32585};
fp.exp < MinExp[fp] AND   bitsZero => {fp.type ← zero; fp.exp ← 0};
fp.exp < MinExp[fp] AND NOT bitsZero => {fp.type ← den; Normalize[fp]};
ENDCASE  => {
fp.type ← norm;
DeNormalize[fp, 1];
fp.exp ← fp.exp-1;
fp.m[0] ← fp.m[0]+100000B} };
FPtoHDW: PROC[fp: FP] RETURNS[hdw: HexDblWord] = {
DblShiftLt: PROC[a, b, n: CARDINAL] RETURNS[CARDINAL] = {
THROUGH (0..n] DO a ← a*2 + b/32768; b ← b*2 ENDLOOP;
RETURN[a]};
exp: CARDINAL;
eSize: CARDINALIF fp.double THEN 11 ELSE 8;
lo, hi: BitOps.BitDWord ← [0,0];
IF fp.exp IN (0..MinExp[fp]) THEN { -- denormalized, assume already rounded
fp.type ← den;
DeNormalize[fp, MinExp[fp]-1-fp.exp]};
SELECT fp.type FROM
nan, inf => exp ← MaxExp[fp]+1-FPExpBias;
zero, den => exp ← 0;
ENDCASE => { -- type=norm, hide msb which should be 1
IF fp.m[0]<100000B THEN ERROR;
ShiftLt[fp]; fp.exp ← fp.exp+1;  -- undo decrement of exp
exp ← fp.exp-(MinExp[fp]-1) };
IF fp.type=zero OR fp.type=inf THEN fp.m ← ALL[0];
IF fp.type=nan THEN fp.m ← ALL[177777B];
hi ← BitOps.IBID[fp.sign,          hi, 32,  0];
hi ← BitOps.ICID[exp,            hi, 32,  1,  eSize];
hi ← BitOps.ICID[DblShiftLt[0,   fp.m[0], 15-eSize], hi, 32, eSize+1, 15-eSize];
hi ← BitOps.ICID[DblShiftLt[fp.m[0], fp.m[1], 15-eSize], hi, 32, 16, 16];
lo ← BitOps.ICID[DblShiftLt[fp.m[1], fp.m[2], 15-eSize], lo, 32,  0,  16];
lo ← BitOps.ICID[DblShiftLt[fp.m[2], fp.m[3], 15-eSize], lo, 32,  16, 16];
hdw.single ← NOT fp.double;
hdw.h  ← BitOps.ELFD[hi,32,0,32];
hdw.l   ← IF fp.double THEN BitOps.ELFD[lo,32,0,32] ELSE 0 };
RoundMult: PROC [fp: FP, mode: Mode] RETURNS[status: Dragon.PBusFaults] = {
fp normalized, (not zero, not inf, not nan)
saveFP: FPRec ← fp^;
exact: BOOL ← Round[fp, mode.rnd];
IF exact THEN status𡤏PgrNEZeroE ELSE status𡤏PneZeroI;
IF fp.exp < MinExp[fp] THEN IF mode.fast
THEN {SetToZero[fp]; exact ← TRUE; RETURN[FPeqZeroE]}
ELSE {
fp^ ← saveFP;
fp.exp ← fp.exp + WrapBias[fp];
IF exact THEN RETURN[FPuFlow] ELSE RETURN[FPuFlowI] };
IF fp.exp > MaxExp[fp] THEN {RETURN[OverFlow[fp, mode.rnd]]} };
RoundFP: PROC [fp: FP, rnd: FPRndMode] RETURNS[status: Dragon.PBusFaults] = {
Possible results: FPeqZeroE, FPlsInfE, FPgrNEZeroE, FPneZeroI, FPoFlowI, FPuFlow, FPuFlowI, FPinvalid
exact: BOOL;
SELECT TRUE FROM
fp.type=nan    => RETURN[FPinvalid];
fp.type=zero    => RETURN[FPeqZeroE];
fp.type=inf    => RETURN[FPlsInfE];
ENDCASE;
exact ← Round[fp, rnd];
IF exact THEN status𡤏PgrNEZeroE ELSE status𡤏PneZeroI;
IF fp.exp < MinExp[fp] THEN IF exact THEN RETURN[FPuFlow] ELSE RETURN[FPuFlowI];
IF fp.exp > MaxExp[fp] THEN RETURN[OverFlow[fp, rnd]] };
Round: PROC[fp: FP, rnd: FPRndMode] RETURNS[exact: BOOL] = {
IF fp.exp<MinExp[fp] THEN DeNormalize[fp, MinExp[fp]-fp.exp];
DeNormalize[fp, (IF fp.double THEN (11-2) ELSE (32+8-2))]; -- rs on right
exact ← Fix[fp, rnd];
fp.m[3] ← Basics.BITAND[fp.m[3], 177774B]; -- Clear RS
Normalize[fp];
RETURN[exact]};
Fix: PROC[fp: FP, rnd: FPRndMode] RETURNS[exact: BOOL] = {
Add: PROC[cy:CARDINAL] = {
FOR i:CARDINAL DECREASING IN [0..3] DO
[cy, fp.m[i]] ← ADC3[fp.m[i], 0, cy] ENDLOOP };
lrs:CARDINAL ← fp.m[3] MOD 8;
IF lrs#0 THEN SELECT rnd FROM
rz => { };
rn => IF lrs=3 OR lrs=6 OR lrs=7 THEN Add[4];
rp => IF NOT fp.sign   THEN Add[3];
rm => IF    fp.sign   THEN Add[3];
ENDCASE;
RETURN[lrs MOD 4 = 0]};
OverFlow: PROC[fp: FP, rnd: FPRndMode] RETURNS[status: Dragon.PBusFaults] = {
SELECT rnd FROM
rn => SetToInf[fp];
rz => SetToMax[fp];
rp => IF fp.sign THEN SetToMax[fp] ELSE SetToInf[fp];
rm => IF fp.sign THEN SetToInf[fp] ELSE SetToMax[fp];
ENDCASE;
RETURN[FPoFlowI] };
Normalize: PROC [fp: FP] = {
IF fp.m[0] = 0 AND fp.m[1] = 0 AND fp.m[2] = 0 AND fp.m[3]/2 = 0 THEN
{SetToZero[fp]; RETURN};
WHILE fp.m[0] = 0 DO
fp.m[0] ← fp.m[1]; fp.m[1] ← fp.m[2]; fp.m[2] ← fp.m[3]; fp.m[3] ← 0;
IF (fp.m[2] MOD 2 = 1) THEN {fp.m[2] ← fp.m[2] - 1; fp.m[3] ← 1};
fp.exp ← fp.exp-16;
ENDLOOP;
WHILE fp.m[0] < 100000B DO
ShiftLt[fp];
IF (fp.m[3] MOD 4 = 2) THEN fp.m[3] ← fp.m[3] - 1;
ENDLOOP };
ShiftLt: PROC [fp: FP] = {
FOR i:CARDINAL IN [0..2] DO
fp.m[i] ← fp.m[i]*2;
IF fp.m[i+1] > 77777B THEN fp.m[i] ← fp.m[i] + 1;
ENDLOOP;
fp.m[3] ← fp.m[3]*2;
fp.exp ← fp.exp-1 };
DeNormalize: PROC [fp: FP, count: INTEGER] = {
WHILE count/16 # 0 DO
fp.m[3] ← fp.m[2] + (IF (fp.m[3]#0) AND ((fp.m[2] MOD 2)=0) THEN 1 ELSE 0);
fp.m[2] ← fp.m[1]; fp.m[1] ← fp.m[0]; fp.m[0] ← 0;
fp.exp ← fp.exp+16;
count ← count-16
ENDLOOP;
THROUGH (0..count] DO
IF (fp.m[3] MOD 3 = 1) THEN fp.m[3] ← fp.m[3] + 2;
ShiftRt[fp, 1];
ENDLOOP };
ShiftRt: PROC [fp: FP, count: CARDINAL] = {
THROUGH (0..count] DO
FOR i:CARDINAL DECREASING IN [1..3] DO
fp.m[i] ← fp.m[i]/2;
IF fp.m[i-1] MOD 2 = 1 THEN fp.m[i] ← fp.m[i] + 100000B;
ENDLOOP;
fp.m[0] ← fp.m[0]/2;
fp.exp ← fp.exp+1;
ENDLOOP };
ADC3: PROC[a, b, c: CARDINAL] RETURNS[cy, sum: CARDINAL] = {
ln: Basics.LongNumber;
ln.lc ← LONG[a] + LONG[b] + LONG[c];
RETURN[ln.highbits, ln.lowbits] };
SignificantBitsZero: PROC[fp:FP] RETURNS[zero:BOOL] = {
IF fp.double
THENRETURN[fp.m[0]=0 AND fp.m[1]=0 AND fp.m[2]=0 AND fp.m[3]/2048=0]
ELSERETURN[fp.m[0]=0 AND fp.m[1]/256=0]};
SetToZero: PROC[fp:FP] = {fp.type←zero; fp.exp𡤀 fp.m←ALL[0]};
SetToNaN: PROC[fp: FP] =
{fp^ ← [fp.double, nan, fp.sign, MaxExp[fp]+1, ALL[177777B]]};
SetToInf: PROC[fp: FP] =
{fp^ ← [fp.double, inf, fp.sign, MaxExp[fp]+1, ALL[0]]};
SetToMax: PROC[fp: FP] =
{fp^ ← [fp.double, norm, fp.sign, MaxExp[fp], ALL[0]];
IF fp.double
THEN {fp.m[0]𡤏p.m[1]𡤏p.m[2]� fp.m[3]�}
ELSE {fp.m[0]� fp.m[1]�}};
MinExp: PROC[fp:FP] RETURNS[CARDINAL] = {
RETURN[(IF fp.double THEN FPExpBias-1022 ELSE FPExpBias-126)]};
MaxExp: PROC[fp:FP] RETURNS[CARDINAL] = {
RETURN[(IF fp.double THEN FPExpBias+1022 ELSE FPExpBias+126)]};
WrapBias: PROC[fp:FP] RETURNS[CARDINAL] = {
RETURN[IF fp.double THEN 2048 ELSE 256]};
END.