udb 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.data/cfgs/rv32-riscv-tests.yaml +5 -1
- data/.data/cfgs/rv64-riscv-tests.yaml +4 -1
- data/.data/spec/std/isa/inst/F/fadd.s.yaml +16 -1
- data/.data/spec/std/isa/inst/F/fclass.s.yaml +7 -0
- data/.data/spec/std/isa/inst/F/fcvt.l.s.yaml +3 -0
- data/.data/spec/std/isa/inst/F/fcvt.lu.s.yaml +3 -0
- data/.data/spec/std/isa/inst/F/fcvt.s.l.yaml +4 -0
- data/.data/spec/std/isa/inst/F/fcvt.s.lu.yaml +4 -0
- data/.data/spec/std/isa/inst/F/fcvt.w.s.yaml +1 -1
- data/.data/spec/std/isa/inst/F/fcvt.wu.s.yaml +1 -1
- data/.data/spec/std/isa/inst/F/fdiv.s.yaml +4 -0
- data/.data/spec/std/isa/inst/F/feq.s.yaml +1 -1
- data/.data/spec/std/isa/inst/F/fle.s.yaml +14 -7
- data/.data/spec/std/isa/inst/F/fleq.s.yaml +30 -0
- data/.data/spec/std/isa/inst/F/flt.s.yaml +13 -8
- data/.data/spec/std/isa/inst/F/fltq.s.yaml +21 -0
- data/.data/spec/std/isa/inst/F/fmadd.s.yaml +4 -0
- data/.data/spec/std/isa/inst/F/fmax.s.yaml +30 -0
- data/.data/spec/std/isa/inst/F/fmin.s.yaml +30 -0
- data/.data/spec/std/isa/inst/F/fmsub.s.yaml +4 -0
- data/.data/spec/std/isa/inst/F/fmul.s.yaml +4 -0
- data/.data/spec/std/isa/inst/F/fnmadd.s.yaml +7 -0
- data/.data/spec/std/isa/inst/F/fnmsub.s.yaml +4 -0
- data/.data/spec/std/isa/inst/F/fsqrt.s.yaml +4 -0
- data/.data/spec/std/isa/isa/fp.idl +911 -101
- data/.data/spec/std/isa/isa/globals.isa +2 -0
- data/.data/spec/std/isa/isa/util.idl +22 -0
- data/lib/udb/cfg_arch.rb +42 -6
- data/lib/udb/condition.rb +66 -2
- data/lib/udb/logic.rb +27 -1
- data/lib/udb/version.rb +1 -1
- metadata +2 -2
|
@@ -21,6 +21,7 @@ Bits<32> SP_NEG_INF = 32'b1_11111111_00000000000000000000000;
|
|
|
21
21
|
Bits<32> SP_POS_ZERO = 32'b0_00000000_00000000000000000000000;
|
|
22
22
|
Bits<32> SP_NEG_ZERO = 32'b1_00000000_00000000000000000000000;
|
|
23
23
|
Bits<32> SP_CANONICAL_NAN = 32'b0_11111111_10000000000000000000000;
|
|
24
|
+
|
|
24
25
|
Bits<16> HP_CANONICAL_NAN = 16'b0_11111_1000000000;
|
|
25
26
|
|
|
26
27
|
Bits<32> WORD_NEG_OVERFLOW = 32'h8000_0000; # minimum signed 32-bit integer
|
|
@@ -32,6 +33,13 @@ Bits<32> UI32_POS_OVERFLOW = 32'hFFFF_FFFF; # maximum unsigned 32-bit integer
|
|
|
32
33
|
Bits<32> UI32_NAN = 32'hFFFF_FFFF; # NaN to unsigned 32-bit integer
|
|
33
34
|
Bits<32> I32_NAN = 32'h7FFF_FFFF; # NaN to signed 32-bit integer
|
|
34
35
|
|
|
36
|
+
Bits<64> I64_NEG_OVERFLOW = 64'h8000_0000_0000_0000; # minimum signed 64-bit integer
|
|
37
|
+
Bits<64> I64_POS_OVERFLOW = 64'h7FFF_FFFF_FFFF_FFFF; # maximum signed 64-bit integer
|
|
38
|
+
Bits<64> UI64_NEG_OVERFLOW = 64'h0000_0000_0000_0000; # minimum unsigned 64-bit integer
|
|
39
|
+
Bits<64> UI64_POS_OVERFLOW = 64'hFFFF_FFFF_FFFF_FFFF; # maximum unsigned 64-bit integer
|
|
40
|
+
Bits<64> UI64_NAN = 64'hFFFF_FFFF_FFFF_FFFF; # NaN to unsigned 64-bit integer
|
|
41
|
+
Bits<64> I64_NAN = 64'h7FFF_FFFF_FFFF_FFFF; # NaN to signed 64-bit integer
|
|
42
|
+
|
|
35
43
|
enum RoundingMode {
|
|
36
44
|
RNE 0b000 # Round to Nearest, ties to Even
|
|
37
45
|
RTZ 0b001 # Round toward Zero
|
|
@@ -49,6 +57,13 @@ enum FpFlag {
|
|
|
49
57
|
NV 0b10000 # Invalid Operation
|
|
50
58
|
}
|
|
51
59
|
|
|
60
|
+
# Operation modifier for fused multiply-add
|
|
61
|
+
enum F32MulAddOp {
|
|
62
|
+
Softfloat_mulAdd_addC 0 # (a * b) + c
|
|
63
|
+
Softfloat_mulAdd_subC 1 # (a * b) - c (negate c)
|
|
64
|
+
Softfloat_mulAdd_subProd 2 # -(a * b) + c (negate product)
|
|
65
|
+
}
|
|
66
|
+
|
|
52
67
|
function set_fp_flag {
|
|
53
68
|
arguments
|
|
54
69
|
FpFlag flag
|
|
@@ -179,10 +194,7 @@ function is_sp_neg_norm? {
|
|
|
179
194
|
return
|
|
180
195
|
(sp_value[31] == 1) # negative
|
|
181
196
|
&& (sp_value[30:23] != 0b11111111) # not inf/NaN
|
|
182
|
-
&&
|
|
183
|
-
(sp_value[30:23] == 0b00000000)
|
|
184
|
-
&& sp_value[22:0] != 0
|
|
185
|
-
);
|
|
197
|
+
&& (sp_value[30:23] != 0b00000000); # not zero or subnormal
|
|
186
198
|
}
|
|
187
199
|
}
|
|
188
200
|
|
|
@@ -194,12 +206,9 @@ function is_sp_pos_norm? {
|
|
|
194
206
|
}
|
|
195
207
|
body {
|
|
196
208
|
return
|
|
197
|
-
(sp_value[31] == 0)
|
|
209
|
+
(sp_value[31] == 0) # positive
|
|
198
210
|
&& (sp_value[30:23] != 0b11111111) # not inf/NaN
|
|
199
|
-
&&
|
|
200
|
-
(sp_value[30:23] == 0b00000000)
|
|
201
|
-
&& sp_value[22:0] != 0
|
|
202
|
-
);
|
|
211
|
+
&& (sp_value[30:23] != 0b00000000); # not zero
|
|
203
212
|
}
|
|
204
213
|
}
|
|
205
214
|
|
|
@@ -308,7 +317,7 @@ function softfloat_shiftRightJam32 {
|
|
|
308
317
|
is zero or nonzero.
|
|
309
318
|
}
|
|
310
319
|
body {
|
|
311
|
-
return (dist < 31) ? a>>dist | ((
|
|
320
|
+
return (dist < 31) ? a>>dist | ((a[dist-1:0] != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
|
|
312
321
|
}
|
|
313
322
|
}
|
|
314
323
|
|
|
@@ -328,7 +337,7 @@ function softfloat_shiftRightJam64 {
|
|
|
328
337
|
is zero or nonzero.
|
|
329
338
|
}
|
|
330
339
|
body {
|
|
331
|
-
return (dist < 63) ? a>>dist | ((
|
|
340
|
+
return (dist < 63) ? a>>dist | ((a[dist-1:0] != 0) ? 1 : 0) : ((a != 0) ? 1 : 0);
|
|
332
341
|
}
|
|
333
342
|
}
|
|
334
343
|
|
|
@@ -383,6 +392,679 @@ function softfloat_roundToI32 {
|
|
|
383
392
|
}
|
|
384
393
|
}
|
|
385
394
|
|
|
395
|
+
function f32_muladd {
|
|
396
|
+
returns U32
|
|
397
|
+
arguments
|
|
398
|
+
U32 a,
|
|
399
|
+
U32 b,
|
|
400
|
+
U32 c,
|
|
401
|
+
F32MulAddOp op,
|
|
402
|
+
RoundingMode mode
|
|
403
|
+
description {
|
|
404
|
+
Fused multiply-add for single-precision floats.
|
|
405
|
+
Computes (a * b) + c, with sign modifications based on op:
|
|
406
|
+
Softfloat_mulAdd_addC: (a * b) + c
|
|
407
|
+
Softfloat_mulAdd_subC: (a * b) - c (negate c)
|
|
408
|
+
Softfloat_mulAdd_subProd: -(a * b) + c (negate product)
|
|
409
|
+
Translated from Berkeley Softfloat softfloat_mulAddF32.
|
|
410
|
+
}
|
|
411
|
+
body {
|
|
412
|
+
Bits<1> signA = signF32UI(a);
|
|
413
|
+
Bits<16> expA = expF32UI(a);
|
|
414
|
+
Bits<32> sigA = fracF32UI(a);
|
|
415
|
+
Bits<1> signB = signF32UI(b);
|
|
416
|
+
Bits<16> expB = expF32UI(b);
|
|
417
|
+
Bits<32> sigB = fracF32UI(b);
|
|
418
|
+
Bits<1> signC = signF32UI(c) ^ ((op == F32MulAddOp::Softfloat_mulAdd_subC) ? 1 : 0);
|
|
419
|
+
Bits<16> expC = expF32UI(c);
|
|
420
|
+
Bits<32> sigC = fracF32UI(c);
|
|
421
|
+
Bits<1> signProd = (signA ^ signB) ^ ((op == F32MulAddOp::Softfloat_mulAdd_subProd) ? 1 : 0);
|
|
422
|
+
|
|
423
|
+
Bits<32> magBits;
|
|
424
|
+
Bits<64> sig64Z;
|
|
425
|
+
|
|
426
|
+
# Handle NaN/Inf in A
|
|
427
|
+
if (expA == 0xFF) {
|
|
428
|
+
if ((sigA != 0) || ((expB == 0xFF) && (sigB != 0))) {
|
|
429
|
+
return SP_CANONICAL_NAN;
|
|
430
|
+
}
|
|
431
|
+
magBits = expB | sigB;
|
|
432
|
+
if (magBits != 0) {
|
|
433
|
+
U32 zA = packToF32UI(signProd, 0xFF, 0);
|
|
434
|
+
if (expC != 0xFF) {
|
|
435
|
+
return zA;
|
|
436
|
+
}
|
|
437
|
+
if (sigC != 0) {
|
|
438
|
+
return SP_CANONICAL_NAN;
|
|
439
|
+
}
|
|
440
|
+
if (signProd == signC) {
|
|
441
|
+
return zA;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
set_fp_flag(FpFlag::NV);
|
|
445
|
+
return SP_CANONICAL_NAN;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
# Handle NaN/Inf in B
|
|
449
|
+
if (expB == 0xFF) {
|
|
450
|
+
if (sigB != 0) {
|
|
451
|
+
return SP_CANONICAL_NAN;
|
|
452
|
+
}
|
|
453
|
+
magBits = expA | sigA;
|
|
454
|
+
if (magBits != 0) {
|
|
455
|
+
U32 zB = packToF32UI(signProd, 0xFF, 0);
|
|
456
|
+
if (expC != 0xFF) {
|
|
457
|
+
return zB;
|
|
458
|
+
}
|
|
459
|
+
if (sigC != 0) {
|
|
460
|
+
return SP_CANONICAL_NAN;
|
|
461
|
+
}
|
|
462
|
+
if (signProd == signC) {
|
|
463
|
+
return zB;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
set_fp_flag(FpFlag::NV);
|
|
467
|
+
return SP_CANONICAL_NAN;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
# Handle NaN/Inf in C
|
|
471
|
+
if (expC == 0xFF) {
|
|
472
|
+
if (sigC != 0) {
|
|
473
|
+
return SP_CANONICAL_NAN;
|
|
474
|
+
}
|
|
475
|
+
return c;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
# Handle zero/subnormal A
|
|
479
|
+
if (expA == 0) {
|
|
480
|
+
if (sigA == 0) {
|
|
481
|
+
if (((expC | sigC) == 0) && (signProd != signC)) {
|
|
482
|
+
return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0);
|
|
483
|
+
}
|
|
484
|
+
return c;
|
|
485
|
+
}
|
|
486
|
+
ExpAndSig norm = softfloat_normSubnormalF32Sig(sigA);
|
|
487
|
+
expA = norm.exp;
|
|
488
|
+
sigA = norm.sig;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
# Handle zero/subnormal B
|
|
492
|
+
if (expB == 0) {
|
|
493
|
+
if (sigB == 0) {
|
|
494
|
+
if (((expC | sigC) == 0) && (signProd != signC)) {
|
|
495
|
+
return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0);
|
|
496
|
+
}
|
|
497
|
+
return c;
|
|
498
|
+
}
|
|
499
|
+
ExpAndSig norm = softfloat_normSubnormalF32Sig(sigB);
|
|
500
|
+
expB = norm.exp;
|
|
501
|
+
sigB = norm.sig;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
# Compute product exponent and significand
|
|
505
|
+
Bits<16> expProd = expA + expB - 16'h007E;
|
|
506
|
+
sigA = (sigA | 32'h00800000) << 7;
|
|
507
|
+
sigB = (sigB | 32'h00800000) << 7;
|
|
508
|
+
U64 sigProd = sigA `* sigB;
|
|
509
|
+
if (sigProd < 64'h2000000000000000) {
|
|
510
|
+
expProd = expProd - 1;
|
|
511
|
+
sigProd = sigProd << 1;
|
|
512
|
+
}
|
|
513
|
+
Bits<1> signZ = signProd;
|
|
514
|
+
Bits<16> expZ;
|
|
515
|
+
Bits<32> sigZ;
|
|
516
|
+
|
|
517
|
+
# Handle zero/subnormal C
|
|
518
|
+
if (expC == 0) {
|
|
519
|
+
if (sigC == 0) {
|
|
520
|
+
expZ = expProd - 1;
|
|
521
|
+
sigZ = softfloat_shiftRightJam64(sigProd, 31);
|
|
522
|
+
return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
|
|
523
|
+
}
|
|
524
|
+
ExpAndSig norm = softfloat_normSubnormalF32Sig(sigC);
|
|
525
|
+
expC = norm.exp;
|
|
526
|
+
sigC = norm.sig;
|
|
527
|
+
}
|
|
528
|
+
sigC = (sigC | 0x00800000) << 6;
|
|
529
|
+
|
|
530
|
+
Bits<16> expDiff = expProd - expC;
|
|
531
|
+
|
|
532
|
+
if (signProd == signC) {
|
|
533
|
+
# Same sign: add magnitudes
|
|
534
|
+
if ($signed(expDiff) <= 0s) {
|
|
535
|
+
expZ = expC;
|
|
536
|
+
sigZ = sigC + softfloat_shiftRightJam64(sigProd, 32 - expDiff);
|
|
537
|
+
} else {
|
|
538
|
+
expZ = expProd;
|
|
539
|
+
sig64Z = sigProd + softfloat_shiftRightJam64(sigC `<< 32, expDiff);
|
|
540
|
+
sigZ = softfloat_shiftRightJam64(sig64Z, 32);
|
|
541
|
+
}
|
|
542
|
+
if (sigZ < 0x40000000) {
|
|
543
|
+
expZ = expZ - 1;
|
|
544
|
+
sigZ = sigZ << 1;
|
|
545
|
+
}
|
|
546
|
+
return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
|
|
547
|
+
} else {
|
|
548
|
+
# Different signs: subtract magnitudes
|
|
549
|
+
U64 sig64C = sigC `<< 32;
|
|
550
|
+
if ($signed(expDiff) < 0s) {
|
|
551
|
+
signZ = signC;
|
|
552
|
+
expZ = expC;
|
|
553
|
+
sig64Z = sig64C - softfloat_shiftRightJam64(sigProd, -expDiff);
|
|
554
|
+
} else if (expDiff == 0) {
|
|
555
|
+
expZ = expProd;
|
|
556
|
+
sig64Z = sigProd - sig64C;
|
|
557
|
+
if (sig64Z == 0) {
|
|
558
|
+
return packToF32UI((mode == RoundingMode::RDN) ? 1 : 0, 0, 0);
|
|
559
|
+
}
|
|
560
|
+
if ((sig64Z & 64'h8000000000000000) != 0) {
|
|
561
|
+
signZ = signZ ^ 1;
|
|
562
|
+
sig64Z = -sig64Z;
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
565
|
+
expZ = expProd;
|
|
566
|
+
sig64Z = sigProd - softfloat_shiftRightJam64(sig64C, expDiff);
|
|
567
|
+
}
|
|
568
|
+
Bits<8> shiftDist = count_leading_zeros_64(64, sig64Z) - 1;
|
|
569
|
+
expZ = expZ - shiftDist;
|
|
570
|
+
shiftDist = shiftDist - 8'h20;
|
|
571
|
+
if ($signed(shiftDist) < 0s) {
|
|
572
|
+
sigZ = softfloat_shiftRightJam64(sig64Z, -shiftDist);
|
|
573
|
+
} else {
|
|
574
|
+
sigZ = sig64Z << shiftDist;
|
|
575
|
+
}
|
|
576
|
+
return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function f32_sqrt {
|
|
582
|
+
returns U32
|
|
583
|
+
arguments
|
|
584
|
+
U32 a,
|
|
585
|
+
RoundingMode mode
|
|
586
|
+
description {
|
|
587
|
+
Computes the square root of a 32-bit floating point number.
|
|
588
|
+
Translated from Berkeley Softfloat f32_sqrt.
|
|
589
|
+
}
|
|
590
|
+
body {
|
|
591
|
+
Bits<1> signA = signF32UI(a);
|
|
592
|
+
Bits<8> expA = expF32UI(a);
|
|
593
|
+
Bits<32> fracA = fracF32UI(a);
|
|
594
|
+
|
|
595
|
+
if (expA == 8'hFF) {
|
|
596
|
+
if (fracA != 0) { return SP_CANONICAL_NAN; }
|
|
597
|
+
if (signA == 0) { return a; }
|
|
598
|
+
set_fp_flag(FpFlag::NV);
|
|
599
|
+
return SP_CANONICAL_NAN;
|
|
600
|
+
}
|
|
601
|
+
if (signA == 1) {
|
|
602
|
+
if ((expA == 0) && (fracA == 0)) { return a; }
|
|
603
|
+
set_fp_flag(FpFlag::NV);
|
|
604
|
+
return SP_CANONICAL_NAN;
|
|
605
|
+
}
|
|
606
|
+
if (expA == 0) {
|
|
607
|
+
if (fracA == 0) { return a; }
|
|
608
|
+
ExpAndSig norm = softfloat_normSubnormalF32Sig(fracA);
|
|
609
|
+
expA = norm.exp;
|
|
610
|
+
fracA = norm.sig;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
Bits<16> expZ = ((expA - 16'h007F) >> 1) + 16'h007E;
|
|
614
|
+
Bits<1> oddExpA = expA[0];
|
|
615
|
+
Bits<32> sigA32 = (fracA | 32'h00800000) << 8;
|
|
616
|
+
Bits<32> sigZ = (sigA32 `* softfloat_approxRecipSqrt32_1(oddExpA, sigA32)) >> 32;
|
|
617
|
+
if (oddExpA == 1) {
|
|
618
|
+
sigZ = sigZ >> 1;
|
|
619
|
+
}
|
|
620
|
+
sigZ = sigZ + 2;
|
|
621
|
+
|
|
622
|
+
if ((sigZ & 0x3F) < 2) {
|
|
623
|
+
Bits<32> shiftedSigZ = sigZ >> 2;
|
|
624
|
+
Bits<32> negRem = shiftedSigZ * shiftedSigZ;
|
|
625
|
+
sigZ = sigZ & ~32'h3;
|
|
626
|
+
if ((negRem & 0x80000000) != 0) {
|
|
627
|
+
sigZ = sigZ | 1;
|
|
628
|
+
} else {
|
|
629
|
+
if (negRem != 0) { sigZ = sigZ - 1; }
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
return softfloat_roundPackToF32(0, expZ, sigZ, mode);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
# Lookup tables for reciprocal and reciprocal-sqrt approximation (Berkeley Softfloat)
|
|
638
|
+
Bits<16> softfloat_approxRecip_1k0s[16] = [
|
|
639
|
+
0xFFC4, 0xF0BE, 0xE363, 0xD76F, 0xCCAD, 0xC2F0, 0xBA16, 0xB201,
|
|
640
|
+
0xAA97, 0xA3C1, 0x9D49, 0x9715, 0x9128, 0x8B7C, 0x8600, 0x80B6
|
|
641
|
+
];
|
|
642
|
+
Bits<16> softfloat_approxRecip_1k1s[16] = [
|
|
643
|
+
0xF0F1, 0xD62C, 0xBFA1, 0xAC77, 0x9C0A, 0x8DDE, 0x8185, 0x7709,
|
|
644
|
+
0x6E7D, 0x6794, 0x6188, 0x5C71, 0x5764, 0x52BE, 0x4E55, 0x4A67
|
|
645
|
+
];
|
|
646
|
+
Bits<16> softfloat_approxRecipSqrt_1k0s[16] = [
|
|
647
|
+
0xB4C9, 0xFFAB, 0xAA7D, 0xF11C, 0xA1C5, 0xE4C7, 0x9A43, 0xDA29,
|
|
648
|
+
0x93B5, 0xD0E5, 0x8DED, 0xC8B7, 0x88C6, 0xC16D, 0x8424, 0xBAE1
|
|
649
|
+
];
|
|
650
|
+
Bits<16> softfloat_approxRecipSqrt_1k1s[16] = [
|
|
651
|
+
0xA5A5, 0xEA42, 0x8C21, 0xC62D, 0x788F, 0xAA7F, 0x6928, 0x94B6,
|
|
652
|
+
0x5CC7, 0x8335, 0x52A6, 0x74EA, 0x4A3E, 0x68C8, 0x42BC, 0x5EFF
|
|
653
|
+
];
|
|
654
|
+
|
|
655
|
+
function softfloat_approxRecip32_1 {
|
|
656
|
+
returns U32
|
|
657
|
+
arguments
|
|
658
|
+
Bits<32> a
|
|
659
|
+
description {
|
|
660
|
+
Returns a 32-bit approximation of 1/a, where a is in [1, 2).
|
|
661
|
+
Translated from Berkeley Softfloat softfloat_approxRecip32_1.
|
|
662
|
+
}
|
|
663
|
+
body {
|
|
664
|
+
Bits<32> index = (a >> 27) & 0xF;
|
|
665
|
+
Bits<16> eps = a >> 11;
|
|
666
|
+
Bits<32> r0 = softfloat_approxRecip_1k0s[index]
|
|
667
|
+
- ((softfloat_approxRecip_1k1s[index] `* eps) >> 20);
|
|
668
|
+
Bits<32> sigma0 = ~((r0 `* a) >> 7);
|
|
669
|
+
Bits<32> r = (r0 << 16) + ((r0 `* sigma0) >> 24);
|
|
670
|
+
Bits<32> sqrSigma0 = (sigma0 `* sigma0) >> 32;
|
|
671
|
+
r = r + ((r `* sqrSigma0) >> 48);
|
|
672
|
+
return r;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function softfloat_approxRecipSqrt32_1 {
|
|
677
|
+
returns U32
|
|
678
|
+
arguments
|
|
679
|
+
Bits<1> oddExpA,
|
|
680
|
+
Bits<32> a
|
|
681
|
+
description {
|
|
682
|
+
Returns a 32-bit approximation of 1/sqrt(a).
|
|
683
|
+
Translated from Berkeley Softfloat softfloat_approxRecipSqrt32_1.
|
|
684
|
+
}
|
|
685
|
+
body {
|
|
686
|
+
Bits<8> index = ((a >> 27) & 0xE) + oddExpA;
|
|
687
|
+
Bits<16> eps = a >> 12;
|
|
688
|
+
Bits<16> r0 = softfloat_approxRecipSqrt_1k0s[index]
|
|
689
|
+
- ((softfloat_approxRecipSqrt_1k1s[index] `* eps) >> 20);
|
|
690
|
+
Bits<32> eSqrR0 = r0 `* r0;
|
|
691
|
+
if (oddExpA == 0) {
|
|
692
|
+
eSqrR0 = eSqrR0 << 1;
|
|
693
|
+
}
|
|
694
|
+
Bits<32> sigma0 = ~((eSqrR0 `* a) >> 23);
|
|
695
|
+
Bits<32> r = (r0 `<< 16) + ((r0 `* sigma0) >> 25);
|
|
696
|
+
Bits<32> sqrSigma0 = (sigma0 `* sigma0) >> 32;
|
|
697
|
+
Bits<32> adj = ((r >> 1) + (r >> 3) - (r0 `<< 14));
|
|
698
|
+
r = r + ((adj `* sqrSigma0) >> 48);
|
|
699
|
+
if ((r & 32'h80000000) == 0) {
|
|
700
|
+
r = 32'h80000000;
|
|
701
|
+
}
|
|
702
|
+
return r;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function f32_div {
|
|
707
|
+
returns U32
|
|
708
|
+
arguments
|
|
709
|
+
U32 a,
|
|
710
|
+
U32 b,
|
|
711
|
+
RoundingMode mode
|
|
712
|
+
description {
|
|
713
|
+
Divides two 32-bit floating point numbers.
|
|
714
|
+
Translated from Berkeley Softfloat f32_div.
|
|
715
|
+
}
|
|
716
|
+
body {
|
|
717
|
+
Bits<1> signA = signF32UI(a);
|
|
718
|
+
Bits<16> expA = expF32UI(a);
|
|
719
|
+
Bits<32> sigA = fracF32UI(a);
|
|
720
|
+
Bits<1> signB = signF32UI(b);
|
|
721
|
+
Bits<16> expB = expF32UI(b);
|
|
722
|
+
Bits<32> sigB = fracF32UI(b);
|
|
723
|
+
Bits<1> signZ = signA ^ signB;
|
|
724
|
+
|
|
725
|
+
Bits<16> expZ;
|
|
726
|
+
|
|
727
|
+
if (expA == 8'hFF) {
|
|
728
|
+
if (sigA != 0) { return SP_CANONICAL_NAN; }
|
|
729
|
+
if (expB == 8'hFF) {
|
|
730
|
+
if (sigB != 0) { return SP_CANONICAL_NAN; }
|
|
731
|
+
set_fp_flag(FpFlag::NV);
|
|
732
|
+
return SP_CANONICAL_NAN;
|
|
733
|
+
}
|
|
734
|
+
return packToF32UI(signZ, 8'hFF, 0);
|
|
735
|
+
}
|
|
736
|
+
if (expB == 8'hFF) {
|
|
737
|
+
if (sigB != 0) { return SP_CANONICAL_NAN; }
|
|
738
|
+
return packToF32UI(signZ, 0, 0);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (expB == 0) {
|
|
742
|
+
if (sigB == 0) {
|
|
743
|
+
if ((expA == 0) && (sigA == 0)) {
|
|
744
|
+
set_fp_flag(FpFlag::NV);
|
|
745
|
+
return SP_CANONICAL_NAN;
|
|
746
|
+
}
|
|
747
|
+
set_fp_flag(FpFlag::DZ);
|
|
748
|
+
return packToF32UI(signZ, 8'hFF, 0);
|
|
749
|
+
}
|
|
750
|
+
ExpAndSig norm = softfloat_normSubnormalF32Sig(sigB);
|
|
751
|
+
expB = norm.exp;
|
|
752
|
+
sigB = norm.sig;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (expA == 0) {
|
|
756
|
+
if (sigA == 0) { return packToF32UI(signZ, 0, 0); }
|
|
757
|
+
ExpAndSig norm = softfloat_normSubnormalF32Sig(sigA);
|
|
758
|
+
expA = norm.exp;
|
|
759
|
+
sigA = norm.sig;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
expZ = expA - expB + 16'h007E;
|
|
763
|
+
sigA = sigA | 32'h00800000;
|
|
764
|
+
sigB = sigB | 32'h00800000;
|
|
765
|
+
|
|
766
|
+
if (sigA < sigB) {
|
|
767
|
+
expZ = expZ - 1;
|
|
768
|
+
sigA = sigA << 8;
|
|
769
|
+
} else {
|
|
770
|
+
sigA = sigA << 7;
|
|
771
|
+
}
|
|
772
|
+
sigB = sigB << 8;
|
|
773
|
+
|
|
774
|
+
Bits<32> recip32 = softfloat_approxRecip32_1(sigB);
|
|
775
|
+
Bits<32> sigZ = (sigA `* recip32) >> 32;
|
|
776
|
+
sigZ = sigZ + 2;
|
|
777
|
+
|
|
778
|
+
if ((sigZ & 0x3F) < 2) {
|
|
779
|
+
sigZ = sigZ & ~32'h3;
|
|
780
|
+
Bits<64> rem = (sigA `<< 31) - (sigZ `* sigB);
|
|
781
|
+
if ((rem & 64'h8000000000000000) != 0) {
|
|
782
|
+
sigZ = sigZ - 4;
|
|
783
|
+
} else {
|
|
784
|
+
if ( rem != 0 ) {
|
|
785
|
+
sigZ = sigZ | 1;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
function f32_mul {
|
|
795
|
+
returns U32
|
|
796
|
+
arguments
|
|
797
|
+
U32 a,
|
|
798
|
+
U32 b,
|
|
799
|
+
RoundingMode mode
|
|
800
|
+
description {
|
|
801
|
+
Multiplies two 32-bit floating point numbers.
|
|
802
|
+
Translated from Berkeley Softfloat f32_mul.
|
|
803
|
+
}
|
|
804
|
+
body {
|
|
805
|
+
Bits<1> signA = signF32UI(a);
|
|
806
|
+
Bits<16> expA = expF32UI(a);
|
|
807
|
+
Bits<23> fracA = fracF32UI(a);
|
|
808
|
+
Bits<1> signB = signF32UI(b);
|
|
809
|
+
Bits<16> expB = expF32UI(b);
|
|
810
|
+
Bits<23> fracB = fracF32UI(b);
|
|
811
|
+
Bits<1> signZ = signA ^ signB;
|
|
812
|
+
|
|
813
|
+
Bits<32> sigA = fracA;
|
|
814
|
+
Bits<32> sigB = fracB;
|
|
815
|
+
Bits<16> expZ;
|
|
816
|
+
Bits<32> sigZ;
|
|
817
|
+
|
|
818
|
+
if (expA == 8'hFF) {
|
|
819
|
+
if ((fracA != 0) || ((expB == 8'hFF) && (fracB != 0))) {
|
|
820
|
+
return SP_CANONICAL_NAN;
|
|
821
|
+
}
|
|
822
|
+
if ((expB == 0) && (fracB == 0)) {
|
|
823
|
+
set_fp_flag(FpFlag::NV);
|
|
824
|
+
return SP_CANONICAL_NAN;
|
|
825
|
+
}
|
|
826
|
+
return packToF32UI(signZ, 8'hFF, 0);
|
|
827
|
+
}
|
|
828
|
+
if (expB == 8'hFF) {
|
|
829
|
+
if (fracB != 0) {
|
|
830
|
+
return SP_CANONICAL_NAN;
|
|
831
|
+
}
|
|
832
|
+
if ((expA == 0) && (fracA == 0)) {
|
|
833
|
+
set_fp_flag(FpFlag::NV);
|
|
834
|
+
return SP_CANONICAL_NAN;
|
|
835
|
+
}
|
|
836
|
+
return packToF32UI(signZ, 8'hFF, 0);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if (expA == 0) {
|
|
840
|
+
if (fracA == 0) { return packToF32UI(signZ, 0, 0); }
|
|
841
|
+
ExpAndSig norm = softfloat_normSubnormalF32Sig(fracA);
|
|
842
|
+
expA = norm.exp;
|
|
843
|
+
sigA = norm.sig;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (expB == 0) {
|
|
847
|
+
if (fracB == 0) { return packToF32UI(signZ, 0, 0); }
|
|
848
|
+
ExpAndSig norm = softfloat_normSubnormalF32Sig(fracB);
|
|
849
|
+
expB = norm.exp;
|
|
850
|
+
sigB = norm.sig;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
expZ = expA + expB - 16'h007F;
|
|
854
|
+
sigA = (sigA | 32'h00800000)<<7;
|
|
855
|
+
sigB = (sigB | 32'h00800000)<<8;
|
|
856
|
+
sigZ = softfloat_shiftRightJam64(sigA `* sigB, 32);
|
|
857
|
+
if (sigZ < 0x40000000 ) {
|
|
858
|
+
expZ = expZ - 1;
|
|
859
|
+
sigZ = sigZ << 1;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function f32_to_i64 {
|
|
867
|
+
returns Bits<64>
|
|
868
|
+
arguments
|
|
869
|
+
U32 a,
|
|
870
|
+
RoundingMode mode
|
|
871
|
+
description {
|
|
872
|
+
Converts 32-bit floating point number to a signed 64-bit integer.
|
|
873
|
+
Translated from Berkeley Softfloat f32_to_i64.
|
|
874
|
+
}
|
|
875
|
+
body {
|
|
876
|
+
Bits<1> sign = signF32UI(a);
|
|
877
|
+
Bits<16> exp = expF32UI(a);
|
|
878
|
+
Bits<32> sig = fracF32UI(a);
|
|
879
|
+
|
|
880
|
+
Bits<16> shiftDist = 16'hBE - exp;
|
|
881
|
+
Bits<64> sig64;
|
|
882
|
+
Bits<64> extra;
|
|
883
|
+
|
|
884
|
+
if ($signed(shiftDist) < 0s) {
|
|
885
|
+
set_fp_flag(FpFlag::NV);
|
|
886
|
+
if ((exp == 16'hFF) && (sig != 0)) {
|
|
887
|
+
return I64_NAN;
|
|
888
|
+
} else {
|
|
889
|
+
return (sign == 1) ? I64_NEG_OVERFLOW : I64_POS_OVERFLOW;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
if (exp != 0) {
|
|
894
|
+
sig = sig | 32'h00800000;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
sig64 = sig `<< 40;
|
|
898
|
+
extra = 0;
|
|
899
|
+
if (shiftDist != 0) {
|
|
900
|
+
TwoU64s sig64Extra = softfloat_shiftRightJam64Extra( sig64, 0, $signed(shiftDist) );
|
|
901
|
+
sig64 = sig64Extra.u1;
|
|
902
|
+
extra = sig64Extra.u2;
|
|
903
|
+
}
|
|
904
|
+
return softfloat_roundToI64( sign, sig64, extra, mode );
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
struct TwoU64s {
|
|
909
|
+
Bits<64> u1;
|
|
910
|
+
Bits<64> u2;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
function softfloat_shiftRightJam64Extra {
|
|
914
|
+
returns TwoU64s
|
|
915
|
+
arguments
|
|
916
|
+
Bits<64> a,
|
|
917
|
+
Bits<64> extra,
|
|
918
|
+
Bits<32> dist
|
|
919
|
+
description {
|
|
920
|
+
Shifts the 128 bits formed by concatenating 'a' and 'extra' right by 64
|
|
921
|
+
_plus_ the number of bits given in 'dist', which must not be zero. This
|
|
922
|
+
shifted value is at most 64 nonzero bits and is returned in the 'v' field
|
|
923
|
+
of the 'struct uint64_extra' result. The 64-bit 'extra' field of the result
|
|
924
|
+
contains a value formed as follows from the bits that were shifted off: The
|
|
925
|
+
_last_ bit shifted off is the most-significant bit of the 'extra' field, and
|
|
926
|
+
the other 63 bits of the 'extra' field are all zero if and only if _all_but_
|
|
927
|
+
_the_last_ bits shifted off were all zero.
|
|
928
|
+
(This function makes more sense if 'a' and 'extra' are considered to form
|
|
929
|
+
an unsigned fixed-point number with binary point between 'a' and 'extra'.
|
|
930
|
+
This fixed-point value is shifted right by the number of bits given in
|
|
931
|
+
'dist', and the integer part of this shifted value is returned in the 'v'
|
|
932
|
+
field of the result. The fractional part of the shifted value is modified
|
|
933
|
+
as described above and returned in the 'extra' field of the result.)
|
|
934
|
+
}
|
|
935
|
+
body {
|
|
936
|
+
TwoU64s z;
|
|
937
|
+
|
|
938
|
+
if (dist < 64) {
|
|
939
|
+
z.u1 = a >> dist;
|
|
940
|
+
z.u2 = a << (-dist & 63);
|
|
941
|
+
} else {
|
|
942
|
+
z.u1 = 0;
|
|
943
|
+
z.u2 = (dist == 64) ? a : ((a != 0) ? 1 : 0);
|
|
944
|
+
}
|
|
945
|
+
z.u2 = z.u2 | ((extra != 0) ? 1 : 0);
|
|
946
|
+
|
|
947
|
+
return z;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
function f32_to_ui64 {
|
|
952
|
+
returns Bits<64>
|
|
953
|
+
arguments
|
|
954
|
+
U32 a,
|
|
955
|
+
RoundingMode mode
|
|
956
|
+
description {
|
|
957
|
+
Converts 32-bit floating point number to an unsigned 64-bit integer.
|
|
958
|
+
Translated from Berkeley Softfloat f32_to_ui64.
|
|
959
|
+
}
|
|
960
|
+
body {
|
|
961
|
+
Bits<1> sign = signF32UI(a);
|
|
962
|
+
Bits<16> exp = expF32UI(a);
|
|
963
|
+
Bits<32> sig = fracF32UI(a);
|
|
964
|
+
|
|
965
|
+
Bits<16> shiftDist;
|
|
966
|
+
Bits<64> sig64, extra;
|
|
967
|
+
|
|
968
|
+
# shiftDist = 0xBE - exp (0xBE = 190 = 127 + 63)
|
|
969
|
+
shiftDist = 16'hBE - exp;
|
|
970
|
+
|
|
971
|
+
if ($signed(shiftDist) < 0s) {
|
|
972
|
+
set_fp_flag(FpFlag::NV);
|
|
973
|
+
if ((exp == 0xFF) && (sig != 0)) {
|
|
974
|
+
return UI64_NAN;
|
|
975
|
+
} else if (sign != 0) {
|
|
976
|
+
return UI64_NEG_OVERFLOW;
|
|
977
|
+
} else {
|
|
978
|
+
return UI64_POS_OVERFLOW;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
if (exp != 0) {
|
|
983
|
+
sig = sig | 32'h00800000;
|
|
984
|
+
}
|
|
985
|
+
sig64 = sig `<< 40;
|
|
986
|
+
extra = 0;
|
|
987
|
+
if (shiftDist != 0) {
|
|
988
|
+
TwoU64s sig64Extra = softfloat_shiftRightJam64Extra(sig64, 0, $signed(shiftDist));
|
|
989
|
+
sig64 = sig64Extra.u1;
|
|
990
|
+
extra = sig64Extra.u2;
|
|
991
|
+
}
|
|
992
|
+
return softfloat_roundToUI64( sign, sig64, extra, mode );
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
function i64_to_f32 {
|
|
997
|
+
returns U32
|
|
998
|
+
arguments
|
|
999
|
+
Bits<64> a,
|
|
1000
|
+
RoundingMode mode
|
|
1001
|
+
description {
|
|
1002
|
+
Converts 64-bit signed integer to 32-bit floating point number.
|
|
1003
|
+
Translated from Berkeley Softfloat i64_to_f32.
|
|
1004
|
+
}
|
|
1005
|
+
body {
|
|
1006
|
+
Bits<1> sign = a[63];
|
|
1007
|
+
Bits<64> absA;
|
|
1008
|
+
|
|
1009
|
+
if (sign == 1) {
|
|
1010
|
+
absA = -a;
|
|
1011
|
+
} else {
|
|
1012
|
+
absA = a;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
# count_leading_zeros<64> returns the number of leading zeros
|
|
1016
|
+
Bits<8> shiftDist = count_leading_zeros(64, absA) - 40;
|
|
1017
|
+
Bits<32> sig;
|
|
1018
|
+
|
|
1019
|
+
if ($signed(shiftDist) >= 0s) {
|
|
1020
|
+
if (a != 0) {
|
|
1021
|
+
return packToF32UI(sign, 16'h95 - shiftDist, absA << shiftDist);
|
|
1022
|
+
} else {
|
|
1023
|
+
return 0;
|
|
1024
|
+
}
|
|
1025
|
+
} else {
|
|
1026
|
+
shiftDist = shiftDist + 7;
|
|
1027
|
+
if ($signed(shiftDist) < 0s) {
|
|
1028
|
+
sig = softfloat_shortShiftRightJam64( absA, -shiftDist );
|
|
1029
|
+
} else {
|
|
1030
|
+
sig = absA << shiftDist;
|
|
1031
|
+
}
|
|
1032
|
+
return softfloat_roundPackToF32(sign, 8'h9C - shiftDist, sig, mode);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function ui64_to_f32 {
|
|
1038
|
+
returns U32
|
|
1039
|
+
arguments
|
|
1040
|
+
Bits<64> a,
|
|
1041
|
+
RoundingMode mode
|
|
1042
|
+
description {
|
|
1043
|
+
Converts 64-bit unsigned integer to 32-bit floating point number.
|
|
1044
|
+
Translated from Berkeley Softfloat ui64_to_f32.
|
|
1045
|
+
}
|
|
1046
|
+
body {
|
|
1047
|
+
Bits<8> shiftDist = count_leading_zeros(64, a) - 40;
|
|
1048
|
+
Bits<32> sig;
|
|
1049
|
+
|
|
1050
|
+
if (0s <= $signed(shiftDist)) {
|
|
1051
|
+
if (a != 0) {
|
|
1052
|
+
return packToF32UI(0, 8'h95 - shiftDist, a << shiftDist);
|
|
1053
|
+
} else {
|
|
1054
|
+
return 0;
|
|
1055
|
+
}
|
|
1056
|
+
} else {
|
|
1057
|
+
shiftDist = shiftDist + 7;
|
|
1058
|
+
if ($signed(shiftDist) < 0s) {
|
|
1059
|
+
sig = softfloat_shortShiftRightJam64(a, -shiftDist);
|
|
1060
|
+
} else {
|
|
1061
|
+
sig = a << shiftDist;
|
|
1062
|
+
}
|
|
1063
|
+
return softfloat_roundPackToF32(0, 8'h9C - shiftDist, sig, mode);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
386
1068
|
function softfloat_roundToUI32 {
|
|
387
1069
|
returns Bits<32>
|
|
388
1070
|
arguments
|
|
@@ -438,12 +1120,12 @@ function packToF32UI {
|
|
|
438
1120
|
arguments
|
|
439
1121
|
Bits<1> sign,
|
|
440
1122
|
Bits<8> exp,
|
|
441
|
-
Bits<
|
|
1123
|
+
Bits<32> sig
|
|
442
1124
|
description {
|
|
443
1125
|
Pack components into a 32-bit value
|
|
444
1126
|
}
|
|
445
1127
|
body {
|
|
446
|
-
return
|
|
1128
|
+
return (sign `<< 31) + (exp `<< 23) + sig;
|
|
447
1129
|
}
|
|
448
1130
|
}
|
|
449
1131
|
|
|
@@ -478,8 +1160,8 @@ function softfloat_roundPackToF32 {
|
|
|
478
1160
|
returns Bits<32> # single precision value
|
|
479
1161
|
arguments
|
|
480
1162
|
Bits<1> sign,
|
|
481
|
-
Bits<
|
|
482
|
-
Bits<
|
|
1163
|
+
Bits<16> exp,
|
|
1164
|
+
Bits<32> sig,
|
|
483
1165
|
RoundingMode mode
|
|
484
1166
|
description {
|
|
485
1167
|
Round FP value according to +mdode+ and then pack it in IEEE format.
|
|
@@ -515,7 +1197,10 @@ function softfloat_roundPackToF32 {
|
|
|
515
1197
|
if (roundBits != 0) {
|
|
516
1198
|
set_fp_flag(FpFlag::NX);
|
|
517
1199
|
}
|
|
518
|
-
|
|
1200
|
+
if ((roundBits == 0x40) && (mode == RoundingMode::RNE)) {
|
|
1201
|
+
sig = sig & ~32'b1; # Clear only the LSB
|
|
1202
|
+
}
|
|
1203
|
+
# sig = sig & ~((((roundBits ^ 0x40) == 0) ? 32'0 : 32'1) & ((mode == RoundingMode::RNE) ? 32'1 : 32'0));
|
|
519
1204
|
if ( sig == 0 ) {
|
|
520
1205
|
exp = 0;
|
|
521
1206
|
}
|
|
@@ -527,8 +1212,8 @@ function softfloat_normRoundPackToF32 {
|
|
|
527
1212
|
returns Bits<32>
|
|
528
1213
|
arguments
|
|
529
1214
|
Bits<1> sign,
|
|
530
|
-
Bits<
|
|
531
|
-
Bits<
|
|
1215
|
+
Bits<16> exp,
|
|
1216
|
+
Bits<32> sig,
|
|
532
1217
|
RoundingMode mode
|
|
533
1218
|
description {
|
|
534
1219
|
Normalize, round, and pack into a 32-bit floating point value
|
|
@@ -635,30 +1320,6 @@ function returnLargerMag {
|
|
|
635
1320
|
}
|
|
636
1321
|
}
|
|
637
1322
|
|
|
638
|
-
function softfloat_propagateNaNF32UI {
|
|
639
|
-
returns U32
|
|
640
|
-
arguments
|
|
641
|
-
U32 a,
|
|
642
|
-
U32 b
|
|
643
|
-
description {
|
|
644
|
-
Interpreting 'a' and 'b' as the bit patterns of two 32-bit floating-
|
|
645
|
-
| point values, at least one of which is a NaN, returns the bit pattern of
|
|
646
|
-
| the combined NaN result. If either 'a' or 'b' has the pattern of a
|
|
647
|
-
| signaling NaN, the invalid exception is raised.
|
|
648
|
-
}
|
|
649
|
-
body {
|
|
650
|
-
# check if a and b are signalling
|
|
651
|
-
Boolean isSigNaN_a = is_sp_signaling_nan?(a);
|
|
652
|
-
Boolean isSigNaN_b = is_sp_signaling_nan?(b);
|
|
653
|
-
|
|
654
|
-
if (isSigNaN_a || isSigNaN_b) {
|
|
655
|
-
# raise invalid flag if either number is NaN
|
|
656
|
-
set_fp_flag(FpFlag::NV);
|
|
657
|
-
}
|
|
658
|
-
return SP_CANONICAL_NAN;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
1323
|
function softfloat_addMagsF32 {
|
|
663
1324
|
returns U32
|
|
664
1325
|
arguments
|
|
@@ -671,10 +1332,10 @@ function softfloat_addMagsF32 {
|
|
|
671
1332
|
body {
|
|
672
1333
|
|
|
673
1334
|
# extract exponents and significands of a and b
|
|
674
|
-
Bits<
|
|
675
|
-
Bits<
|
|
676
|
-
Bits<
|
|
677
|
-
Bits<
|
|
1335
|
+
Bits<16> expA = expF32UI(a);
|
|
1336
|
+
Bits<32> sigA = fracF32UI(a);
|
|
1337
|
+
Bits<16> expB = expF32UI(b);
|
|
1338
|
+
Bits<32> sigB = fracF32UI(b);
|
|
678
1339
|
|
|
679
1340
|
# declare a variable to store significand of sum
|
|
680
1341
|
U32 sigZ;
|
|
@@ -687,9 +1348,9 @@ function softfloat_addMagsF32 {
|
|
|
687
1348
|
Bits<8> expZ;
|
|
688
1349
|
|
|
689
1350
|
# calculate difference of exponents
|
|
690
|
-
Bits<
|
|
1351
|
+
Bits<16> expDiff = expA - expB;
|
|
691
1352
|
|
|
692
|
-
if (expDiff ==
|
|
1353
|
+
if (expDiff == 16'd0) {
|
|
693
1354
|
if (expA == 8'd0) {
|
|
694
1355
|
z = a + b;
|
|
695
1356
|
return z; # if exponents of both numbers are zero, then return sum of both numbers
|
|
@@ -699,7 +1360,7 @@ function softfloat_addMagsF32 {
|
|
|
699
1360
|
if (expA == 8'hFF) {
|
|
700
1361
|
# A is NaN if significand is non-zero and exponent is 8'hFF
|
|
701
1362
|
if ((sigA != 8'd0) || (sigB != 8'd0)) {
|
|
702
|
-
return
|
|
1363
|
+
return SP_CANONICAL_NAN;
|
|
703
1364
|
}
|
|
704
1365
|
# return infinity if A is infinity
|
|
705
1366
|
return a;
|
|
@@ -722,47 +1383,47 @@ function softfloat_addMagsF32 {
|
|
|
722
1383
|
|
|
723
1384
|
signZ = signF32UI(a);
|
|
724
1385
|
|
|
725
|
-
|
|
726
|
-
|
|
1386
|
+
sigA = sigA << 6;
|
|
1387
|
+
sigB = sigB << 6;
|
|
727
1388
|
|
|
728
1389
|
# check if B has a bigger exponent value than A
|
|
729
|
-
if (expDiff <
|
|
1390
|
+
if ($signed(expDiff) < 0s) {
|
|
730
1391
|
# check if B is infinity or NaN
|
|
731
1392
|
if (expB == 8'hFF) {
|
|
732
1393
|
# B is NaN if exponent is 8'hFF and significand is non-zero
|
|
733
1394
|
if (sigB != 0) {
|
|
734
|
-
return
|
|
1395
|
+
return SP_CANONICAL_NAN;
|
|
735
1396
|
}
|
|
736
1397
|
# return infinity with same sign as A
|
|
737
1398
|
return packToF32UI(signZ, 8'hFF, 23'h0);
|
|
738
1399
|
}
|
|
739
1400
|
expZ = expB;
|
|
740
1401
|
|
|
741
|
-
|
|
742
|
-
|
|
1402
|
+
sigA = (expA == 0) ? 2*sigA : (sigA + 0x20000000);
|
|
1403
|
+
sigA = softfloat_shiftRightJam32(sigA, -expDiff);
|
|
743
1404
|
} else {
|
|
744
1405
|
# check if A is infinity or NaN
|
|
745
1406
|
if (expA == 8'hFF) {
|
|
746
1407
|
# A is NaN if exponent is 8'hFF and significand is non-zero
|
|
747
1408
|
if (sigA != 0) {
|
|
748
|
-
return
|
|
1409
|
+
return SP_CANONICAL_NAN;
|
|
749
1410
|
}
|
|
750
1411
|
# return infinity with same sign as A
|
|
751
1412
|
return a;
|
|
752
1413
|
}
|
|
753
1414
|
|
|
754
1415
|
expZ = expA;
|
|
755
|
-
|
|
756
|
-
|
|
1416
|
+
sigB = (expB == 0) ? 2*sigB : (sigB + 0x20000000);
|
|
1417
|
+
sigB = softfloat_shiftRightJam32(sigB, expDiff);
|
|
757
1418
|
}
|
|
758
1419
|
|
|
759
|
-
|
|
1420
|
+
sigZ = 0x20000000 + sigA + sigB;
|
|
760
1421
|
if ( sigZ < 0x40000000 ) {
|
|
761
1422
|
expZ = expZ - 1;
|
|
762
1423
|
sigZ = sigZ << 1;
|
|
763
1424
|
}
|
|
764
1425
|
}
|
|
765
|
-
return softfloat_roundPackToF32(signZ, expZ, sigZ
|
|
1426
|
+
return softfloat_roundPackToF32(signZ, expZ, sigZ, mode);
|
|
766
1427
|
}
|
|
767
1428
|
}
|
|
768
1429
|
|
|
@@ -778,10 +1439,10 @@ function softfloat_subMagsF32 {
|
|
|
778
1439
|
body {
|
|
779
1440
|
|
|
780
1441
|
# extract exponents and significands of a and b
|
|
781
|
-
Bits<
|
|
782
|
-
Bits<
|
|
783
|
-
Bits<
|
|
784
|
-
Bits<
|
|
1442
|
+
Bits<16> expA = expF32UI(a);
|
|
1443
|
+
Bits<32> sigA = fracF32UI(a);
|
|
1444
|
+
Bits<16> expB = expF32UI(b);
|
|
1445
|
+
Bits<32> sigB = fracF32UI(b);
|
|
785
1446
|
|
|
786
1447
|
# declare a variable to store significand of difference
|
|
787
1448
|
U32 sigZ;
|
|
@@ -800,26 +1461,18 @@ function softfloat_subMagsF32 {
|
|
|
800
1461
|
U32 sigX;
|
|
801
1462
|
U32 sigY;
|
|
802
1463
|
|
|
803
|
-
# declare a U32 sigA and sigB
|
|
804
|
-
U32 sigA_32;
|
|
805
|
-
U32 sigB_32;
|
|
806
|
-
|
|
807
1464
|
# declare a variable to store shift distance
|
|
808
1465
|
Bits<8> shiftDist;
|
|
809
1466
|
|
|
810
1467
|
# calculate difference of exponents
|
|
811
|
-
Bits<
|
|
1468
|
+
Bits<16> expDiff = expA - expB;
|
|
812
1469
|
|
|
813
|
-
if (expDiff ==
|
|
1470
|
+
if (expDiff == 16'd0) {
|
|
814
1471
|
|
|
815
1472
|
# check if A is infinity or NaN
|
|
816
1473
|
if (expA == 8'hFF) {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
return softfloat_propagateNaNF32UI(a, b);
|
|
820
|
-
}
|
|
821
|
-
# return infinity if A is infinity
|
|
822
|
-
return a;
|
|
1474
|
+
set_fp_flag(FpFlag::NV);
|
|
1475
|
+
return SP_CANONICAL_NAN;
|
|
823
1476
|
}
|
|
824
1477
|
|
|
825
1478
|
sigDiff = sigA - sigB;
|
|
@@ -855,30 +1508,30 @@ function softfloat_subMagsF32 {
|
|
|
855
1508
|
} else {
|
|
856
1509
|
# when difference in exponents are not zero
|
|
857
1510
|
signZ = signF32UI(a);
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
if (expDiff <
|
|
1511
|
+
sigA = sigA << 7;
|
|
1512
|
+
sigB = sigB << 7;
|
|
1513
|
+
if ($signed(expDiff) < 0s) {
|
|
861
1514
|
signZ = ~signZ;
|
|
862
1515
|
if (expB == 0xFF) {
|
|
863
|
-
if (
|
|
864
|
-
return
|
|
1516
|
+
if (sigB != 0) {
|
|
1517
|
+
return SP_CANONICAL_NAN;
|
|
865
1518
|
}
|
|
866
1519
|
return packToF32UI(signZ, expB, 0);
|
|
867
1520
|
}
|
|
868
1521
|
expZ = expB - 1;
|
|
869
|
-
sigX =
|
|
870
|
-
sigY =
|
|
1522
|
+
sigX = sigB | 0x40000000;
|
|
1523
|
+
sigY = sigA + ((expA != 0) ? 0x40000000 : sigA);
|
|
871
1524
|
expDiff = - expDiff;
|
|
872
1525
|
} else {
|
|
873
1526
|
if (expA == 0xFF) {
|
|
874
|
-
if (
|
|
875
|
-
return
|
|
1527
|
+
if (sigA != 0) {
|
|
1528
|
+
return SP_CANONICAL_NAN;
|
|
876
1529
|
}
|
|
877
1530
|
return a;
|
|
878
1531
|
}
|
|
879
1532
|
expZ = expA - 1;
|
|
880
|
-
sigX =
|
|
881
|
-
sigY =
|
|
1533
|
+
sigX = sigA | 0x40000000;
|
|
1534
|
+
sigY = sigB + ((expB != 0) ? 0x40000000 : sigB);
|
|
882
1535
|
}
|
|
883
1536
|
return softfloat_normRoundPackToF32(signZ, expZ, sigX - softfloat_shiftRightJam32(sigY, expDiff), mode);
|
|
884
1537
|
}
|
|
@@ -941,8 +1594,8 @@ function i32_to_f32 {
|
|
|
941
1594
|
if ((a & 0x7FFFFFFF) == 0) {
|
|
942
1595
|
return (sign == 1) ? packToF32UI(1, 0x9E, 0) : packToF32UI(0, 0, 0);
|
|
943
1596
|
}
|
|
944
|
-
U32
|
|
945
|
-
return softfloat_normRoundPackToF32(sign, 0x9C,
|
|
1597
|
+
U32 absA = (sign == 1) ? -a : a;
|
|
1598
|
+
return softfloat_normRoundPackToF32(sign, 0x9C, absA, mode);
|
|
946
1599
|
}
|
|
947
1600
|
}
|
|
948
1601
|
|
|
@@ -977,9 +1630,9 @@ function f32_to_i32 {
|
|
|
977
1630
|
}
|
|
978
1631
|
body {
|
|
979
1632
|
Bits<1> sign = signF32UI(a);
|
|
980
|
-
Bits<
|
|
981
|
-
Bits<
|
|
982
|
-
Bits<
|
|
1633
|
+
Bits<16> exp = expF32UI(a);
|
|
1634
|
+
Bits<32> sig = fracF32UI(a);
|
|
1635
|
+
Bits<16> shiftDist;
|
|
983
1636
|
U64 sig64;
|
|
984
1637
|
# for NaN return the highest positive value and set floating-point flag to invalid.
|
|
985
1638
|
if ((exp == 8'hFF) && (sig != 0)) {
|
|
@@ -996,7 +1649,7 @@ function f32_to_i32 {
|
|
|
996
1649
|
sig64 = sig `<< 32;
|
|
997
1650
|
shiftDist = 8'hAA - exp;
|
|
998
1651
|
|
|
999
|
-
if (shiftDist >
|
|
1652
|
+
if ($signed(shiftDist) > 0s) {
|
|
1000
1653
|
sig64 = softfloat_shiftRightJam64( sig64, shiftDist);
|
|
1001
1654
|
}
|
|
1002
1655
|
|
|
@@ -1014,9 +1667,9 @@ function f32_to_ui32 {
|
|
|
1014
1667
|
}
|
|
1015
1668
|
body {
|
|
1016
1669
|
Bits<1> sign = signF32UI(a);
|
|
1017
|
-
Bits<
|
|
1018
|
-
Bits<
|
|
1019
|
-
Bits<
|
|
1670
|
+
Bits<16> exp = expF32UI(a);
|
|
1671
|
+
Bits<32> sig = fracF32UI(a);
|
|
1672
|
+
Bits<16> shiftDist;
|
|
1020
1673
|
U64 sig64;
|
|
1021
1674
|
# for NaN return the highest positive value and set floating-point flag to invalid.
|
|
1022
1675
|
if ((exp == 8'hFF) && (sig != 0)) {
|
|
@@ -1033,7 +1686,7 @@ function f32_to_ui32 {
|
|
|
1033
1686
|
sig64 = sig `<< 32;
|
|
1034
1687
|
shiftDist = 8'hAA - exp;
|
|
1035
1688
|
|
|
1036
|
-
if (shiftDist >
|
|
1689
|
+
if ($signed(shiftDist) > 0s) {
|
|
1037
1690
|
sig64 = softfloat_shiftRightJam64( sig64, shiftDist);
|
|
1038
1691
|
}
|
|
1039
1692
|
|
|
@@ -1045,8 +1698,8 @@ function softfloat_roundPackToF32_no_flag {
|
|
|
1045
1698
|
returns Bits<32> # single precision value
|
|
1046
1699
|
arguments
|
|
1047
1700
|
Bits<1> sign,
|
|
1048
|
-
Bits<
|
|
1049
|
-
Bits<
|
|
1701
|
+
Bits<16> exp,
|
|
1702
|
+
Bits<32> sig,
|
|
1050
1703
|
RoundingMode mode
|
|
1051
1704
|
description {
|
|
1052
1705
|
Round FP value according to +mdode+ and then pack it in IEEE format.
|
|
@@ -1087,8 +1740,8 @@ function softfloat_normRoundPackToF32_no_flag {
|
|
|
1087
1740
|
returns Bits<32>
|
|
1088
1741
|
arguments
|
|
1089
1742
|
Bits<1> sign,
|
|
1090
|
-
Bits<
|
|
1091
|
-
Bits<
|
|
1743
|
+
Bits<16> exp,
|
|
1744
|
+
Bits<32> sig,
|
|
1092
1745
|
RoundingMode mode
|
|
1093
1746
|
description {
|
|
1094
1747
|
Normalize, round, and pack into a 32-bit floating point value
|
|
@@ -1235,3 +1888,160 @@ function round_f32_to_integral {
|
|
|
1235
1888
|
return i32_to_f32_no_flag(intermediate, mode);
|
|
1236
1889
|
}
|
|
1237
1890
|
}
|
|
1891
|
+
|
|
1892
|
+
struct ExpAndSig {
|
|
1893
|
+
Bits<8> exp;
|
|
1894
|
+
Bits<32> sig;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
function softfloat_normSubnormalF32Sig {
|
|
1898
|
+
returns ExpAndSig
|
|
1899
|
+
arguments
|
|
1900
|
+
Bits<32> sig
|
|
1901
|
+
description {
|
|
1902
|
+
Normalize a subnormal F32 significand.
|
|
1903
|
+
Returns (exp, sig32) where exp is the adjusted exponent (two's complement
|
|
1904
|
+
in Bits<8>) and sig32 is the normalized significand with implicit leading 1
|
|
1905
|
+
at bit 23.
|
|
1906
|
+
}
|
|
1907
|
+
body {
|
|
1908
|
+
Bits<8> shiftDist = count_leading_zeros(32, sig) - 8;
|
|
1909
|
+
ExpAndSig ret;
|
|
1910
|
+
ret.exp = 1 - shiftDist;
|
|
1911
|
+
ret.sig = sig << shiftDist;
|
|
1912
|
+
return ret;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
function softfloat_shortShiftRightJam64 {
|
|
1917
|
+
returns Bits<64>
|
|
1918
|
+
arguments
|
|
1919
|
+
Bits<64> a,
|
|
1920
|
+
Bits<8> dist
|
|
1921
|
+
description {
|
|
1922
|
+
Shifts +a+ right by +dist+ bits (dist must be in 1..31), jamming any
|
|
1923
|
+
shifted-off bits into the least-significant bit of the result.
|
|
1924
|
+
}
|
|
1925
|
+
body {
|
|
1926
|
+
return a >> dist | (((a & ((64'h1 << dist) - 1)) != 0) ? 1 : 0);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
function softfloat_roundToI64 {
|
|
1931
|
+
returns Bits<64>
|
|
1932
|
+
arguments
|
|
1933
|
+
Bits<1> sign,
|
|
1934
|
+
Bits<64> sig,
|
|
1935
|
+
Bits<64> sigExtra,
|
|
1936
|
+
RoundingMode roundingMode
|
|
1937
|
+
description {
|
|
1938
|
+
Round to signed 64-bit integer, using +roundingMode+.
|
|
1939
|
+
Translated from Berkeley Softfloat softfloat_roundToI64.
|
|
1940
|
+
}
|
|
1941
|
+
body {
|
|
1942
|
+
Bits<64> z;
|
|
1943
|
+
Boolean needs_increment = false;
|
|
1944
|
+
|
|
1945
|
+
if ((roundingMode == RoundingMode::RMM) || (roundingMode == RoundingMode::RNE)) {
|
|
1946
|
+
if (64'h8000000000000000 <= sigExtra) {
|
|
1947
|
+
needs_increment = true;
|
|
1948
|
+
}
|
|
1949
|
+
} else {
|
|
1950
|
+
if ((sigExtra != 0) && ((sign != 0) ? (roundingMode == RoundingMode::RDN) : (roundingMode == RoundingMode::RUP))) {
|
|
1951
|
+
needs_increment = true;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
if (needs_increment) {
|
|
1956
|
+
sig = sig + 1;
|
|
1957
|
+
if (sig == 0) {
|
|
1958
|
+
set_fp_flag(FpFlag::NV);
|
|
1959
|
+
return (sign == 1) ? I64_NEG_OVERFLOW : I64_POS_OVERFLOW;
|
|
1960
|
+
}
|
|
1961
|
+
if ((sigExtra == 64'h8000000000000000) && (roundingMode == RoundingMode::RNE)) {
|
|
1962
|
+
sig = sig & ~64'h1;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
z = (sign == 1) ? -sig : sig;
|
|
1967
|
+
if ((z != 0) && (((($signed(z) < 0s) ? 1 : 0) ^ sign) == 1)) {
|
|
1968
|
+
set_fp_flag(FpFlag::NV);
|
|
1969
|
+
return (sign == 1) ? I64_NEG_OVERFLOW : I64_POS_OVERFLOW;
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
if (sigExtra != 0) {
|
|
1973
|
+
set_fp_flag(FpFlag::NX);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
return z;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
function softfloat_roundToUI64 {
|
|
1981
|
+
returns Bits<64>
|
|
1982
|
+
arguments
|
|
1983
|
+
Bits<1> sign,
|
|
1984
|
+
Bits<64> sig,
|
|
1985
|
+
Bits<64> sigExtra,
|
|
1986
|
+
RoundingMode roundingMode
|
|
1987
|
+
description {
|
|
1988
|
+
Round to unsigned 64-bit integer, using +roundingMode+.
|
|
1989
|
+
Translated from Berkeley Softfloat softfloat_roundToUI64.
|
|
1990
|
+
}
|
|
1991
|
+
body {
|
|
1992
|
+
Boolean needs_increment = false;
|
|
1993
|
+
|
|
1994
|
+
if ((roundingMode == RoundingMode::RMM) || (roundingMode == RoundingMode::RNE)) {
|
|
1995
|
+
if (64'h8000000000000000 <= sigExtra) {
|
|
1996
|
+
needs_increment = true;
|
|
1997
|
+
}
|
|
1998
|
+
} else {
|
|
1999
|
+
if (sign != 0) {
|
|
2000
|
+
if ((sig | sigExtra) == 0) {
|
|
2001
|
+
return 0;
|
|
2002
|
+
}
|
|
2003
|
+
if (roundingMode == RoundingMode::RDN) {
|
|
2004
|
+
set_fp_flag(FpFlag::NV);
|
|
2005
|
+
if (sign == 1) {
|
|
2006
|
+
return UI64_NEG_OVERFLOW;
|
|
2007
|
+
} else {
|
|
2008
|
+
return UI64_POS_OVERFLOW;
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
} else {
|
|
2012
|
+
if ( (roundingMode == RoundingMode::RUP) && (sigExtra != 0)) {
|
|
2013
|
+
needs_increment = true;
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
if (needs_increment) {
|
|
2019
|
+
sig = sig + 1;
|
|
2020
|
+
if (sig == 0) {
|
|
2021
|
+
set_fp_flag(FpFlag::NV);
|
|
2022
|
+
if (sign == 1) {
|
|
2023
|
+
return UI64_NEG_OVERFLOW;
|
|
2024
|
+
} else {
|
|
2025
|
+
return UI64_POS_OVERFLOW;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
if ( (sigExtra == 64'h8000000000000000) && (roundingMode == RoundingMode::RNE)) {
|
|
2029
|
+
sig = sig & ~64'h1;
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
if ( (sign != 0) && (sig != 0) ) {
|
|
2034
|
+
set_fp_flag(FpFlag::NV);
|
|
2035
|
+
if (sign == 1) {
|
|
2036
|
+
return UI64_NEG_OVERFLOW;
|
|
2037
|
+
} else {
|
|
2038
|
+
return UI64_POS_OVERFLOW;
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
if (sigExtra != 0) {
|
|
2043
|
+
set_fp_flag(FpFlag::NX);
|
|
2044
|
+
}
|
|
2045
|
+
return sig;
|
|
2046
|
+
}
|
|
2047
|
+
}
|