1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Const
, Elaboratable
6 from nmigen
.cli
import main
, verilog
9 from ieee754
.fpcommon
.fpbase
import FPNumDecode
10 from nmutil
.singlepipe
import StageChain
11 from ieee754
.pipeline
import DynamicPipe
13 from ieee754
.fpcommon
.fpbase
import FPState
, FPID
, FPNumBaseRecord
14 from ieee754
.fpcommon
.getop
import FPADDBaseData
15 from ieee754
.fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
)
18 class FPAddSpecialCasesMod(Elaboratable
):
19 """ special cases: NaNs, infs, zeros, denormalised
20 NOTE: some of these are unique to add. see "Special Operations"
21 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
24 def __init__(self
, pspec
):
30 return FPADDBaseData(self
.pspec
)
33 return FPSCData(self
.pspec
, True)
35 def setup(self
, m
, i
):
36 """ links module to inputs and outputs
38 m
.submodules
.specialcases
= self
39 m
.d
.comb
+= self
.i
.eq(i
)
44 def elaborate(self
, platform
):
47 #m.submodules.sc_out_z = self.o.z
49 # decode: XXX really should move to separate stage
50 width
= self
.pspec
.width
51 a1
= FPNumBaseRecord(width
)
52 b1
= FPNumBaseRecord(width
)
53 m
.submodules
.sc_decode_a
= a1
= FPNumDecode(None, a1
)
54 m
.submodules
.sc_decode_b
= b1
= FPNumDecode(None, b1
)
55 m
.d
.comb
+= [a1
.v
.eq(self
.i
.a
),
61 s_nomatch
= Signal(reset_less
=True)
62 m
.d
.comb
+= s_nomatch
.eq(a1
.s
!= b1
.s
)
64 m_match
= Signal(reset_less
=True)
65 m
.d
.comb
+= m_match
.eq(a1
.m
== b1
.m
)
67 e_match
= Signal(reset_less
=True)
68 m
.d
.comb
+= e_match
.eq(a1
.e
== b1
.e
)
70 aeqmb
= Signal(reset_less
=True)
71 m
.d
.comb
+= aeqmb
.eq(s_nomatch
& m_match
& e_match
)
73 abz
= Signal(reset_less
=True)
74 m
.d
.comb
+= abz
.eq(a1
.is_zero
& b1
.is_zero
)
76 abnan
= Signal(reset_less
=True)
77 m
.d
.comb
+= abnan
.eq(a1
.is_nan | b1
.is_nan
)
79 bexp128s
= Signal(reset_less
=True)
80 m
.d
.comb
+= bexp128s
.eq(b1
.exp_128
& s_nomatch
)
83 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
85 # if a is NaN or b is NaN return NaN
87 m
.d
.comb
+= self
.o
.z
.nan(0)
89 # XXX WEIRDNESS for FP16 non-canonical NaN handling
92 ## if a is zero and b is NaN return -b
93 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
94 # m.d.comb += self.o.out_do_z.eq(1)
95 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
97 ## if b is zero and a is NaN return -a
98 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
99 # m.d.comb += self.o.out_do_z.eq(1)
100 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
102 ## if a is -zero and b is NaN return -b
103 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
104 # m.d.comb += self.o.out_do_z.eq(1)
105 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
107 ## if b is -zero and a is NaN return -a
108 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
109 # m.d.comb += self.o.out_do_z.eq(1)
110 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
112 # if a is inf return inf (or NaN)
113 with m
.Elif(a1
.is_inf
):
114 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
115 # if a is inf and signs don't match return NaN
117 m
.d
.comb
+= self
.o
.z
.nan(0)
119 # if b is inf return inf
120 with m
.Elif(b1
.is_inf
):
121 m
.d
.comb
+= self
.o
.z
.inf(b1
.s
)
123 # if a is zero and b zero return signed-a/b
125 m
.d
.comb
+= self
.o
.z
.create(a1
.s
& b1
.s
, b1
.e
, b1
.m
[3:-1])
127 # if a is zero return b
128 with m
.Elif(a1
.is_zero
):
129 m
.d
.comb
+= self
.o
.z
.create(b1
.s
, b1
.e
, b1
.m
[3:-1])
131 # if b is zero return a
132 with m
.Elif(b1
.is_zero
):
133 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[3:-1])
135 # if a equal to -b return zero (+ve zero)
137 m
.d
.comb
+= self
.o
.z
.zero(0)
139 # Denormalised Number checks next, so pass a/b data through
141 m
.d
.comb
+= self
.o
.out_do_z
.eq(0)
143 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
144 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
149 class FPAddSpecialCases(FPState
):
150 """ special cases: NaNs, infs, zeros, denormalised
151 NOTE: some of these are unique to add. see "Special Operations"
152 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
155 def __init__(self
, width
, id_wid
):
156 FPState
.__init
__(self
, "special_cases")
157 self
.mod
= FPAddSpecialCasesMod(width
)
158 self
.out_z
= self
.mod
.ospec()
159 self
.out_do_z
= Signal(reset_less
=True)
161 def setup(self
, m
, i
):
162 """ links module to inputs and outputs
164 self
.mod
.setup(m
, i
, self
.out_do_z
)
165 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
166 m
.d
.sync
+= self
.out_z
.ctx
.eq(self
.mod
.o
.ctx
) # (and mid)
170 with m
.If(self
.out_do_z
):
173 m
.next
= "denormalise"
176 class FPAddSpecialCasesDeNorm(DynamicPipe
):
177 """ special cases: NaNs, infs, zeros, denormalised
178 NOTE: some of these are unique to add. see "Special Operations"
179 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
182 def __init__(self
, pspec
):
184 super().__init
__(pspec
)
185 self
.out
= self
.ospec()
188 return FPADDBaseData(self
.pspec
) # SC ispec
191 return FPSCData(self
.pspec
, True) # DeNorm
193 def setup(self
, m
, i
):
194 """ links module to inputs and outputs
196 smod
= FPAddSpecialCasesMod(self
.pspec
)
197 dmod
= FPAddDeNormMod(self
.pspec
, True)
199 chain
= StageChain([smod
, dmod
])
202 # only needed for break-out (early-out)
203 # self.out_do_z = smod.o.out_do_z
207 def process(self
, i
):