1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Mux
, Elaboratable
6 from nmigen
.cli
import main
, verilog
9 from ieee754
.fpcommon
.fpbase
import (Overflow
, OverflowMod
,
10 FPNumBase
, FPNumBaseRecord
)
11 from ieee754
.fpcommon
.fpbase
import FPState
12 from ieee754
.fpcommon
.getop
import FPPipeContext
13 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
14 from ieee754
.fpcommon
.exphigh
import FPEXPHigh
15 from .postcalc
import FPAddStage1Data
20 def __init__(self
, pspec
):
22 self
.roundz
= Signal(reset_less
=True, name
="norm1_roundz")
23 self
.z
= FPNumBaseRecord(width
, False)
24 self
.out_do_z
= Signal(reset_less
=True)
25 self
.oz
= Signal(width
, reset_less
=True)
26 self
.ctx
= FPPipeContext(pspec
)
27 self
.muxid
= self
.ctx
.muxid
30 ret
= [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
31 self
.roundz
.eq(i
.roundz
), self
.ctx
.eq(i
.ctx
)]
35 class FPNorm1ModSingle(Elaboratable
):
37 def __init__(self
, pspec
, e_extra
=False):
39 self
.e_extra
= e_extra
44 return FPAddStage1Data(self
.pspec
, e_extra
=self
.e_extra
)
47 return FPNorm1Data(self
.pspec
)
49 def setup(self
, m
, i
):
50 """ links module to inputs and outputs
52 m
.submodules
.normalise_1
= self
53 m
.d
.comb
+= self
.i
.eq(i
)
58 def elaborate(self
, platform
):
61 of
= OverflowMod("norm1of_")
63 #m.submodules.norm1_out_z = self.o.z
64 m
.submodules
.norm1_out_overflow
= of
65 #m.submodules.norm1_in_z = self.i.z
66 #m.submodules.norm1_in_overflow = self.i.of
69 i
.of
.guard
.name
= "norm1_i_of_guard"
70 i
.of
.round_bit
.name
= "norm1_i_of_roundbit"
71 i
.of
.sticky
.name
= "norm1_i_of_sticky"
72 i
.of
.m0
.name
= "norm1_i_of_m0"
73 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
74 #m.submodules.norm1_insel_overflow = iof = OverflowMod("iof")
76 espec
= (len(insel_z
.e
), True)
77 mwid
= self
.o
.z
.m_width
+2
79 msr
= FPEXPHigh(mwid
+2, espec
[0])
80 m
.submodules
.norm_exp
= msr
82 msb
= FPMSBHigh(mwid
+1, espec
[0], True)
83 m
.submodules
.norm_msb
= msb
85 m
.d
.comb
+= i
.eq(self
.i
)
86 # initialise out from in (overridden below)
87 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
88 m
.d
.comb
+= Overflow
.eq(of
, i
.of
)
89 # normalisation increase/decrease conditions
90 decrease
= Signal(reset_less
=True)
91 increase
= Signal(reset_less
=True)
92 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
93 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
95 with m
.If(~self
.i
.out_do_z
):
96 # concatenate s/r/g with mantissa
97 temp_m
= Signal(mwid
+2, reset_less
=True)
98 m
.d
.comb
+= temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
102 # make sure that the amount to decrease by does NOT
103 # go below the minimum non-INF/NaN exponent
104 m
.d
.comb
+= msb
.limclz
.eq(insel_z
.exp_sub_n126
)
106 # inputs: mantissa and exponent
108 msb
.e_in
.eq(insel_z
.e
),
110 # outputs: mantissa first (s/r/g/m[3:])
111 self
.o
.z
.m
.eq(msb
.m_out
[3:]), # exclude bits 0&1
112 of
.m0
.eq(msb
.m_out
[3]), # copy of mantissa[0]
113 # overflow in bits 0..1: got shifted too (leave sticky)
114 of
.guard
.eq(msb
.m_out
[2]), # guard
115 of
.round_bit
.eq(msb
.m_out
[1]), # round
117 self
.o
.z
.e
.eq(msb
.e_out
),
120 with m
.Elif(increase
):
121 ediff_n126
= Signal(espec
, reset_less
=True)
124 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
125 # connect multi-shifter to inp/out m/e (and ediff)
127 msr
.e_in
.eq(insel_z
.e
),
128 msr
.ediff
.eq(ediff_n126
),
130 # outputs: mantissa first (s/r/g/m[3:])
131 self
.o
.z
.m
.eq(msr
.m_out
[3:]),
132 of
.m0
.eq(msr
.m_out
[3]), # copy of mantissa[0]
133 # overflow in bits 0..2: got shifted too (leave sticky)
134 of
.guard
.eq(msr
.m_out
[2]), # guard
135 of
.round_bit
.eq(msr
.m_out
[1]), # round
136 of
.sticky
.eq(msr
.m_out
[0]), # sticky
138 self
.o
.z
.e
.eq(msr
.e_out
),
141 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz_out
)
142 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
143 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
144 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
149 class FPNorm1ModMulti
:
151 def __init__(self
, pspec
, single_cycle
=True):
153 self
.in_select
= Signal(reset_less
=True)
154 self
.in_z
= FPNumBase(width
, False)
155 self
.in_of
= Overflow()
156 self
.temp_z
= FPNumBase(width
, False)
157 self
.temp_of
= Overflow()
158 self
.out_z
= FPNumBase(width
, False)
159 self
.out_of
= Overflow()
161 def elaborate(self
, platform
):
164 m
.submodules
.norm1_out_z
= self
.out_z
165 m
.submodules
.norm1_out_overflow
= self
.out_of
166 m
.submodules
.norm1_temp_z
= self
.temp_z
167 m
.submodules
.norm1_temp_of
= self
.temp_of
168 m
.submodules
.norm1_in_z
= self
.in_z
169 m
.submodules
.norm1_in_overflow
= self
.in_of
171 in_z
= FPNumBase(self
.width
, False)
173 m
.submodules
.norm1_insel_z
= in_z
174 m
.submodules
.norm1_insel_overflow
= in_of
176 # select which of temp or in z/of to use
177 with m
.If(self
.in_select
):
178 m
.d
.comb
+= in_z
.eq(self
.in_z
)
179 m
.d
.comb
+= in_of
.eq(self
.in_of
)
181 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
182 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
183 # initialise out from in (overridden below)
184 m
.d
.comb
+= self
.out_z
.eq(in_z
)
185 m
.d
.comb
+= self
.out_of
.eq(in_of
)
186 # normalisation increase/decrease conditions
187 decrease
= Signal(reset_less
=True)
188 increase
= Signal(reset_less
=True)
189 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
190 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
191 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
195 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
196 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
197 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
198 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
199 self
.out_of
.round_bit
.eq(0), # reset round bit
200 self
.out_of
.m0
.eq(in_of
.guard
),
203 with m
.Elif(increase
):
205 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
206 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
207 self
.out_of
.guard
.eq(in_z
.m
[0]),
208 self
.out_of
.m0
.eq(in_z
.m
[1]),
209 self
.out_of
.round_bit
.eq(in_of
.guard
),
210 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
216 class FPNorm1Single(FPState
):
218 def __init__(self
, width
, id_wid
, single_cycle
=True):
219 FPState
.__init
__(self
, "normalise_1")
220 self
.mod
= FPNorm1ModSingle(width
)
221 self
.o
= self
.ospec()
222 self
.out_z
= FPNumBase(width
, False)
223 self
.out_roundz
= Signal(reset_less
=True)
226 return self
.mod
.ispec()
229 return self
.mod
.ospec()
231 def setup(self
, m
, i
):
232 """ links module to inputs and outputs
240 class FPNorm1Multi(FPState
):
242 def __init__(self
, width
, id_wid
):
243 FPState
.__init
__(self
, "normalise_1")
244 self
.mod
= FPNorm1ModMulti(width
)
245 self
.stb
= Signal(reset_less
=True)
246 self
.ack
= Signal(reset
=0, reset_less
=True)
247 self
.out_norm
= Signal(reset_less
=True)
248 self
.in_accept
= Signal(reset_less
=True)
249 self
.temp_z
= FPNumBase(width
)
250 self
.temp_of
= Overflow()
251 self
.out_z
= FPNumBase(width
)
252 self
.out_roundz
= Signal(reset_less
=True)
254 def setup(self
, m
, in_z
, in_of
, norm_stb
):
255 """ links module to inputs and outputs
257 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
258 self
.in_accept
, self
.temp_z
, self
.temp_of
,
259 self
.out_z
, self
.out_norm
)
261 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
262 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
265 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
266 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
267 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
268 with m
.If(self
.out_norm
):
269 with m
.If(self
.in_accept
):
274 m
.d
.sync
+= self
.ack
.eq(0)
276 # normalisation not required (or done).
278 m
.d
.sync
+= self
.ack
.eq(1)
279 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)