1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Const
6 from nmigen
.cli
import main
, verilog
9 from nmutil
.pipemodbase
import PipeModBase
, PipeModBaseChain
10 from ieee754
.fpcommon
.fpbase
import FPNumDecode
12 from ieee754
.fpcommon
.fpbase
import FPNumBaseRecord
13 from ieee754
.fpcommon
.basedata
import FPBaseData
14 from ieee754
.fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
)
17 class FPAddSpecialCasesMod(PipeModBase
):
18 """ special cases: NaNs, infs, zeros, denormalised
19 NOTE: some of these are unique to add. see "Special Operations"
20 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
23 def __init__(self
, pspec
):
24 super().__init
__(pspec
, "specialcases")
27 return FPBaseData(self
.pspec
)
30 return FPSCData(self
.pspec
, True)
32 def elaborate(self
, platform
):
36 # decode: XXX really should move to separate stage
37 width
= self
.pspec
.width
38 a1
= FPNumBaseRecord(width
)
39 b1
= FPNumBaseRecord(width
)
40 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
41 m
.submodules
.sc_decode_b
= b1
= FPNumDecode(None, b1
)
42 comb
+= [a1
.v
.eq(self
.i
.a
),
48 # temporaries used below
49 s_nomatch
= Signal(reset_less
=True)
50 m_match
= Signal(reset_less
=True)
51 e_match
= Signal(reset_less
=True)
52 aeqmb
= Signal(reset_less
=True)
53 abz
= Signal(reset_less
=True)
54 abnan
= Signal(reset_less
=True)
55 bexp128s
= Signal(reset_less
=True)
57 comb
+= s_nomatch
.eq(a1
.s
!= b1
.s
)
58 comb
+= m_match
.eq(a1
.m
== b1
.m
)
59 comb
+= e_match
.eq(a1
.e
== b1
.e
)
60 comb
+= aeqmb
.eq(s_nomatch
& m_match
& e_match
)
61 comb
+= abz
.eq(a1
.is_zero
& b1
.is_zero
)
62 comb
+= abnan
.eq(a1
.is_nan | b1
.is_nan
)
63 comb
+= bexp128s
.eq(b1
.exp_128
& s_nomatch
)
66 comb
+= self
.o
.out_do_z
.eq(1)
68 # if a is NaN or b is NaN return NaN
70 comb
+= self
.o
.z
.nan(0)
72 # XXX WEIRDNESS for FP16 non-canonical NaN handling
75 ## if a is zero and b is NaN return -b
76 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
77 # comb += self.o.out_do_z.eq(1)
78 # comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
80 ## if b is zero and a is NaN return -a
81 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
82 # comb += self.o.out_do_z.eq(1)
83 # comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
85 ## if a is -zero and b is NaN return -b
86 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
87 # comb += self.o.out_do_z.eq(1)
88 # comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
90 ## if b is -zero and a is NaN return -a
91 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
92 # comb += self.o.out_do_z.eq(1)
93 # comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
95 # if a is inf return inf (or NaN)
96 with m
.Elif(a1
.is_inf
):
97 comb
+= self
.o
.z
.inf(a1
.s
)
98 # if a is inf and signs don't match return NaN
100 comb
+= self
.o
.z
.nan(0)
102 # if b is inf return inf
103 with m
.Elif(b1
.is_inf
):
104 comb
+= self
.o
.z
.inf(b1
.s
)
106 # if a is zero and b zero return signed-a/b
108 comb
+= self
.o
.z
.create(a1
.s
& b1
.s
, b1
.e
, b1
.m
[3:-1])
110 # if a is zero return b
111 with m
.Elif(a1
.is_zero
):
112 comb
+= self
.o
.z
.create(b1
.s
, b1
.e
, b1
.m
[3:-1])
114 # if b is zero return a
115 with m
.Elif(b1
.is_zero
):
116 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[3:-1])
118 # if a equal to -b return zero (+ve zero)
120 comb
+= self
.o
.z
.zero(0)
122 # Denormalised Number checks next, so pass a/b data through
124 comb
+= self
.o
.out_do_z
.eq(0)
126 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
127 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
132 class FPAddSpecialCasesDeNorm(PipeModBaseChain
):
133 """ special cases chain
137 """ links module to inputs and outputs
139 smod
= FPAddSpecialCasesMod(self
.pspec
)
140 dmod
= FPAddDeNormMod(self
.pspec
, True)