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
.lib
.coding
import PriorityEncoder
7 from nmigen
.cli
import main
, verilog
10 from fpbase
import Overflow
, FPNumBase
11 from fpbase
import MultiShiftRMerge
12 from fpbase
import FPState
13 from .postcalc
import FPAddStage1Data
18 def __init__(self
, width
, id_wid
):
19 self
.roundz
= Signal(reset_less
=True)
20 self
.z
= FPNumBase(width
, False)
21 self
.out_do_z
= Signal(reset_less
=True)
22 self
.oz
= Signal(width
, reset_less
=True)
23 self
.mid
= Signal(id_wid
, reset_less
=True)
26 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
27 self
.roundz
.eq(i
.roundz
), self
.mid
.eq(i
.mid
)]
30 class FPNorm1ModSingle(Elaboratable
):
32 def __init__(self
, width
, id_wid
):
39 return FPAddStage1Data(self
.width
, self
.id_wid
)
42 return FPNorm1Data(self
.width
, self
.id_wid
)
44 def setup(self
, m
, i
):
45 """ links module to inputs and outputs
47 m
.submodules
.normalise_1
= self
48 m
.d
.comb
+= self
.i
.eq(i
)
53 def elaborate(self
, platform
):
56 mwid
= self
.o
.z
.m_width
+2
57 pe
= PriorityEncoder(mwid
)
58 m
.submodules
.norm_pe
= pe
61 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz
)
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 m
.submodules
.norm1_insel_z
= i
.z
70 m
.submodules
.norm1_insel_overflow
= i
.of
72 espec
= (len(i
.z
.e
), True)
73 ediff_n126
= Signal(espec
, reset_less
=True)
74 msr
= MultiShiftRMerge(mwid
, espec
)
75 m
.submodules
.multishift_r
= msr
77 m
.d
.comb
+= i
.eq(self
.i
)
78 # initialise out from in (overridden below)
79 m
.d
.comb
+= self
.o
.z
.eq(i
.z
)
80 m
.d
.comb
+= of
.eq(i
.of
)
81 # normalisation increase/decrease conditions
82 decrease
= Signal(reset_less
=True)
83 increase
= Signal(reset_less
=True)
84 m
.d
.comb
+= decrease
.eq(i
.z
.m_msbzero
& i
.z
.exp_gt_n126
)
85 m
.d
.comb
+= increase
.eq(i
.z
.exp_lt_n126
)
87 with m
.If(~self
.i
.out_do_z
):
89 # *sigh* not entirely obvious: count leading zeros (clz)
90 # with a PriorityEncoder: to find from the MSB
91 # we reverse the order of the bits.
92 temp_m
= Signal(mwid
, reset_less
=True)
93 temp_s
= Signal(mwid
+1, reset_less
=True)
94 clz
= Signal((len(i
.z
.e
), True), reset_less
=True)
95 # make sure that the amount to decrease by does NOT
96 # go below the minimum non-INF/NaN exponent
97 limclz
= Mux(i
.z
.exp_sub_n126
> pe
.o
, pe
.o
,
100 # cat round and guard bits back into the mantissa
101 temp_m
.eq(Cat(i
.of
.round_bit
, i
.of
.guard
, i
.z
.m
)),
102 pe
.i
.eq(temp_m
[::-1]), # inverted
103 clz
.eq(limclz
), # count zeros from MSB down
104 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
105 self
.o
.z
.e
.eq(i
.z
.e
- clz
), # DECREASE exponent
106 self
.o
.z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
107 of
.m0
.eq(temp_s
[2]), # copy of mantissa[0]
108 # overflow in bits 0..1: got shifted too (leave sticky)
109 of
.guard
.eq(temp_s
[1]), # guard
110 of
.round_bit
.eq(temp_s
[0]), # round
113 with m
.Elif(increase
):
114 temp_m
= Signal(mwid
+1, reset_less
=True)
116 temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
118 ediff_n126
.eq(i
.z
.N126
- i
.z
.e
),
119 # connect multi-shifter to inp/out mantissa (and ediff)
121 msr
.diff
.eq(ediff_n126
),
122 self
.o
.z
.m
.eq(msr
.m
[3:]),
123 of
.m0
.eq(temp_s
[3]), # copy of mantissa[0]
124 # overflow in bits 0..1: got shifted too (leave sticky)
125 of
.guard
.eq(temp_s
[2]), # guard
126 of
.round_bit
.eq(temp_s
[1]), # round
127 of
.sticky
.eq(temp_s
[0]), # sticky
128 self
.o
.z
.e
.eq(i
.z
.e
+ ediff_n126
),
131 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
132 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
133 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
138 class FPNorm1ModMulti
:
140 def __init__(self
, width
, single_cycle
=True):
142 self
.in_select
= Signal(reset_less
=True)
143 self
.in_z
= FPNumBase(width
, False)
144 self
.in_of
= Overflow()
145 self
.temp_z
= FPNumBase(width
, False)
146 self
.temp_of
= Overflow()
147 self
.out_z
= FPNumBase(width
, False)
148 self
.out_of
= Overflow()
150 def elaborate(self
, platform
):
153 m
.submodules
.norm1_out_z
= self
.out_z
154 m
.submodules
.norm1_out_overflow
= self
.out_of
155 m
.submodules
.norm1_temp_z
= self
.temp_z
156 m
.submodules
.norm1_temp_of
= self
.temp_of
157 m
.submodules
.norm1_in_z
= self
.in_z
158 m
.submodules
.norm1_in_overflow
= self
.in_of
160 in_z
= FPNumBase(self
.width
, False)
162 m
.submodules
.norm1_insel_z
= in_z
163 m
.submodules
.norm1_insel_overflow
= in_of
165 # select which of temp or in z/of to use
166 with m
.If(self
.in_select
):
167 m
.d
.comb
+= in_z
.eq(self
.in_z
)
168 m
.d
.comb
+= in_of
.eq(self
.in_of
)
170 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
171 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
172 # initialise out from in (overridden below)
173 m
.d
.comb
+= self
.out_z
.eq(in_z
)
174 m
.d
.comb
+= self
.out_of
.eq(in_of
)
175 # normalisation increase/decrease conditions
176 decrease
= Signal(reset_less
=True)
177 increase
= Signal(reset_less
=True)
178 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
179 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
180 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
184 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
185 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
186 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
187 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
188 self
.out_of
.round_bit
.eq(0), # reset round bit
189 self
.out_of
.m0
.eq(in_of
.guard
),
192 with m
.Elif(increase
):
194 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
195 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
196 self
.out_of
.guard
.eq(in_z
.m
[0]),
197 self
.out_of
.m0
.eq(in_z
.m
[1]),
198 self
.out_of
.round_bit
.eq(in_of
.guard
),
199 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
205 class FPNorm1Single(FPState
):
207 def __init__(self
, width
, id_wid
, single_cycle
=True):
208 FPState
.__init
__(self
, "normalise_1")
209 self
.mod
= FPNorm1ModSingle(width
)
210 self
.o
= self
.ospec()
211 self
.out_z
= FPNumBase(width
, False)
212 self
.out_roundz
= Signal(reset_less
=True)
215 return self
.mod
.ispec()
218 return self
.mod
.ospec()
220 def setup(self
, m
, i
):
221 """ links module to inputs and outputs
229 class FPNorm1Multi(FPState
):
231 def __init__(self
, width
, id_wid
):
232 FPState
.__init
__(self
, "normalise_1")
233 self
.mod
= FPNorm1ModMulti(width
)
234 self
.stb
= Signal(reset_less
=True)
235 self
.ack
= Signal(reset
=0, reset_less
=True)
236 self
.out_norm
= Signal(reset_less
=True)
237 self
.in_accept
= Signal(reset_less
=True)
238 self
.temp_z
= FPNumBase(width
)
239 self
.temp_of
= Overflow()
240 self
.out_z
= FPNumBase(width
)
241 self
.out_roundz
= Signal(reset_less
=True)
243 def setup(self
, m
, in_z
, in_of
, norm_stb
):
244 """ links module to inputs and outputs
246 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
247 self
.in_accept
, self
.temp_z
, self
.temp_of
,
248 self
.out_z
, self
.out_norm
)
250 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
251 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
254 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
255 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
256 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
257 with m
.If(self
.out_norm
):
258 with m
.If(self
.in_accept
):
263 m
.d
.sync
+= self
.ack
.eq(0)
265 # normalisation not required (or done).
267 m
.d
.sync
+= self
.ack
.eq(1)
268 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)