13d4c18220b66a4f7765a85c4fdc30c6e753b169
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 ieee754
.fpcommon
.modbase
import FPModBase
10 from ieee754
.fpcommon
.fpbase
import FPNumDecode
11 from nmutil
.singlepipe
import StageChain
12 from ieee754
.pipeline
import DynamicPipe
14 from ieee754
.fpcommon
.fpbase
import FPNumBaseRecord
15 from ieee754
.fpcommon
.getop
import FPADDBaseData
16 from ieee754
.fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
)
19 class FPAddSpecialCasesMod(FPModBase
):
20 """ special cases: NaNs, infs, zeros, denormalised
21 NOTE: some of these are unique to add. see "Special Operations"
22 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
25 def __init__(self
, pspec
):
26 super().__init
__(pspec
, "specialcases")
29 return FPADDBaseData(self
.pspec
)
32 return FPSCData(self
.pspec
, True)
34 def elaborate(self
, platform
):
38 # decode: XXX really should move to separate stage
39 width
= self
.pspec
.width
40 a1
= FPNumBaseRecord(width
)
41 b1
= FPNumBaseRecord(width
)
42 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
43 m
.submodules
.sc_decode_b
= b1
= FPNumDecode(None, b1
)
44 comb
+= [a1
.v
.eq(self
.i
.a
),
50 # temporaries used below
51 s_nomatch
= Signal(reset_less
=True)
52 m_match
= Signal(reset_less
=True)
53 e_match
= Signal(reset_less
=True)
54 aeqmb
= Signal(reset_less
=True)
55 abz
= Signal(reset_less
=True)
56 abnan
= Signal(reset_less
=True)
57 bexp128s
= Signal(reset_less
=True)
59 comb
+= s_nomatch
.eq(a1
.s
!= b1
.s
)
60 comb
+= m_match
.eq(a1
.m
== b1
.m
)
61 comb
+= e_match
.eq(a1
.e
== b1
.e
)
62 comb
+= aeqmb
.eq(s_nomatch
& m_match
& e_match
)
63 comb
+= abz
.eq(a1
.is_zero
& b1
.is_zero
)
64 comb
+= abnan
.eq(a1
.is_nan | b1
.is_nan
)
65 comb
+= bexp128s
.eq(b1
.exp_128
& s_nomatch
)
68 comb
+= self
.o
.out_do_z
.eq(1)
70 # if a is NaN or b is NaN return NaN
72 comb
+= self
.o
.z
.nan(0)
74 # XXX WEIRDNESS for FP16 non-canonical NaN handling
77 ## if a is zero and b is NaN return -b
78 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
79 # comb += self.o.out_do_z.eq(1)
80 # comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
82 ## if b is zero and a is NaN return -a
83 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
84 # comb += self.o.out_do_z.eq(1)
85 # comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
87 ## if a is -zero and b is NaN return -b
88 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
89 # comb += self.o.out_do_z.eq(1)
90 # comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
92 ## if b is -zero and a is NaN return -a
93 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
94 # comb += self.o.out_do_z.eq(1)
95 # comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
97 # if a is inf return inf (or NaN)
98 with m
.Elif(a1
.is_inf
):
99 comb
+= self
.o
.z
.inf(a1
.s
)
100 # if a is inf and signs don't match return NaN
102 comb
+= self
.o
.z
.nan(0)
104 # if b is inf return inf
105 with m
.Elif(b1
.is_inf
):
106 comb
+= self
.o
.z
.inf(b1
.s
)
108 # if a is zero and b zero return signed-a/b
110 comb
+= self
.o
.z
.create(a1
.s
& b1
.s
, b1
.e
, b1
.m
[3:-1])
112 # if a is zero return b
113 with m
.Elif(a1
.is_zero
):
114 comb
+= self
.o
.z
.create(b1
.s
, b1
.e
, b1
.m
[3:-1])
116 # if b is zero return a
117 with m
.Elif(b1
.is_zero
):
118 comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[3:-1])
120 # if a equal to -b return zero (+ve zero)
122 comb
+= self
.o
.z
.zero(0)
124 # Denormalised Number checks next, so pass a/b data through
126 comb
+= self
.o
.out_do_z
.eq(0)
128 comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
129 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
134 class FPAddSpecialCasesDeNorm(DynamicPipe
):
135 """ special cases: NaNs, infs, zeros, denormalised
136 NOTE: some of these are unique to add. see "Special Operations"
137 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
140 def __init__(self
, pspec
):
142 super().__init
__(pspec
)
145 return FPADDBaseData(self
.pspec
) # SC ispec
148 return FPSCData(self
.pspec
, True) # DeNorm
150 def setup(self
, m
, i
):
151 """ links module to inputs and outputs
153 smod
= FPAddSpecialCasesMod(self
.pspec
)
154 dmod
= FPAddDeNormMod(self
.pspec
, True)
156 chain
= StageChain([smod
, dmod
])
159 # only needed for break-out (early-out)
160 # self.out_do_z = smod.o.out_do_z
164 def process(self
, i
):