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 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 FPAddSpecialCasesDeNorm(DynamicPipe
):
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
, pspec
):
157 super().__init
__(pspec
)
158 self
.out
= self
.ospec()
161 return FPADDBaseData(self
.pspec
) # SC ispec
164 return FPSCData(self
.pspec
, True) # DeNorm
166 def setup(self
, m
, i
):
167 """ links module to inputs and outputs
169 smod
= FPAddSpecialCasesMod(self
.pspec
)
170 dmod
= FPAddDeNormMod(self
.pspec
, True)
172 chain
= StageChain([smod
, dmod
])
175 # only needed for break-out (early-out)
176 # self.out_do_z = smod.o.out_do_z
180 def process(self
, i
):