95e49174237882c081a526f0592ba504d33c7f39
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 ieee754
.fpcommon
.fpbase
import Overflow
, FPNumBase
, FPNumBaseRecord
11 from ieee754
.fpcommon
.fpbase
import MultiShiftRMerge
12 from ieee754
.fpcommon
.fpbase
import FPState
13 from ieee754
.fpcommon
.getop
import FPPipeContext
14 from .postcalc
import FPAddStage1Data
19 def __init__(self
, width
, pspec
):
20 self
.roundz
= Signal(reset_less
=True, name
="norm1_roundz")
21 self
.z
= FPNumBaseRecord(width
, False)
22 self
.out_do_z
= Signal(reset_less
=True)
23 self
.oz
= Signal(width
, reset_less
=True)
24 self
.ctx
= FPPipeContext(width
, pspec
)
25 self
.muxid
= self
.ctx
.muxid
28 ret
= [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
29 self
.roundz
.eq(i
.roundz
), self
.ctx
.eq(i
.ctx
)]
33 class FPNorm1ModSingle(Elaboratable
):
35 def __init__(self
, width
, pspec
):
42 return FPAddStage1Data(self
.width
, self
.pspec
)
45 return FPNorm1Data(self
.width
, self
.pspec
)
47 def setup(self
, m
, i
):
48 """ links module to inputs and outputs
50 m
.submodules
.normalise_1
= self
51 m
.d
.comb
+= self
.i
.eq(i
)
56 def elaborate(self
, platform
):
59 mwid
= self
.o
.z
.m_width
+2
60 pe
= PriorityEncoder(mwid
)
61 m
.submodules
.norm_pe
= pe
64 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz
)
66 #m.submodules.norm1_out_z = self.o.z
67 #m.submodules.norm1_out_overflow = of
68 #m.submodules.norm1_in_z = self.i.z
69 #m.submodules.norm1_in_overflow = self.i.of
72 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
73 #m.submodules.norm1_insel_overflow = i.of
75 espec
= (len(insel_z
.e
), True)
76 ediff_n126
= Signal(espec
, reset_less
=True)
77 msr
= MultiShiftRMerge(mwid
+2, espec
)
78 m
.submodules
.multishift_r
= msr
80 m
.d
.comb
+= i
.eq(self
.i
)
81 # initialise out from in (overridden below)
82 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
83 m
.d
.comb
+= of
.eq(i
.of
)
84 # normalisation increase/decrease conditions
85 decrease
= Signal(reset_less
=True)
86 increase
= Signal(reset_less
=True)
87 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
88 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
90 with m
.If(~self
.i
.out_do_z
):
92 # *sigh* not entirely obvious: count leading zeros (clz)
93 # with a PriorityEncoder: to find from the MSB
94 # we reverse the order of the bits.
95 temp_m
= Signal(mwid
, reset_less
=True)
96 temp_s
= Signal(mwid
+1, reset_less
=True)
97 clz
= Signal((len(insel_z
.e
), True), reset_less
=True)
98 # make sure that the amount to decrease by does NOT
99 # go below the minimum non-INF/NaN exponent
100 limclz
= Mux(insel_z
.exp_sub_n126
> pe
.o
, pe
.o
,
101 insel_z
.exp_sub_n126
)
103 # cat round and guard bits back into the mantissa
104 temp_m
.eq(Cat(i
.of
.round_bit
, i
.of
.guard
, insel_z
.m
)),
105 pe
.i
.eq(temp_m
[::-1]), # inverted
106 clz
.eq(limclz
), # count zeros from MSB down
107 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
108 self
.o
.z
.e
.eq(insel_z
.e
- clz
), # DECREASE exponent
109 self
.o
.z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
110 of
.m0
.eq(temp_s
[2]), # copy of mantissa[0]
111 # overflow in bits 0..1: got shifted too (leave sticky)
112 of
.guard
.eq(temp_s
[1]), # guard
113 of
.round_bit
.eq(temp_s
[0]), # round
116 with m
.Elif(increase
):
117 temp_m
= Signal(mwid
+1, reset_less
=True)
119 temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
121 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
122 # connect multi-shifter to inp/out mantissa (and ediff)
124 msr
.diff
.eq(ediff_n126
),
125 self
.o
.z
.m
.eq(msr
.m
[3:]),
126 of
.m0
.eq(msr
.m
[3]), # copy of mantissa[0]
127 # overflow in bits 0..1: got shifted too (leave sticky)
128 of
.guard
.eq(msr
.m
[2]), # guard
129 of
.round_bit
.eq(msr
.m
[1]), # round
130 of
.sticky
.eq(msr
.m
[0]), # sticky
131 self
.o
.z
.e
.eq(insel_z
.e
+ ediff_n126
),
134 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
135 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
136 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
141 class FPNorm1ModMulti
:
143 def __init__(self
, width
, single_cycle
=True):
145 self
.in_select
= Signal(reset_less
=True)
146 self
.in_z
= FPNumBase(width
, False)
147 self
.in_of
= Overflow()
148 self
.temp_z
= FPNumBase(width
, False)
149 self
.temp_of
= Overflow()
150 self
.out_z
= FPNumBase(width
, False)
151 self
.out_of
= Overflow()
153 def elaborate(self
, platform
):
156 m
.submodules
.norm1_out_z
= self
.out_z
157 m
.submodules
.norm1_out_overflow
= self
.out_of
158 m
.submodules
.norm1_temp_z
= self
.temp_z
159 m
.submodules
.norm1_temp_of
= self
.temp_of
160 m
.submodules
.norm1_in_z
= self
.in_z
161 m
.submodules
.norm1_in_overflow
= self
.in_of
163 in_z
= FPNumBase(self
.width
, False)
165 m
.submodules
.norm1_insel_z
= in_z
166 m
.submodules
.norm1_insel_overflow
= in_of
168 # select which of temp or in z/of to use
169 with m
.If(self
.in_select
):
170 m
.d
.comb
+= in_z
.eq(self
.in_z
)
171 m
.d
.comb
+= in_of
.eq(self
.in_of
)
173 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
174 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
175 # initialise out from in (overridden below)
176 m
.d
.comb
+= self
.out_z
.eq(in_z
)
177 m
.d
.comb
+= self
.out_of
.eq(in_of
)
178 # normalisation increase/decrease conditions
179 decrease
= Signal(reset_less
=True)
180 increase
= Signal(reset_less
=True)
181 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
182 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
183 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
187 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
188 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
189 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
190 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
191 self
.out_of
.round_bit
.eq(0), # reset round bit
192 self
.out_of
.m0
.eq(in_of
.guard
),
195 with m
.Elif(increase
):
197 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
198 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
199 self
.out_of
.guard
.eq(in_z
.m
[0]),
200 self
.out_of
.m0
.eq(in_z
.m
[1]),
201 self
.out_of
.round_bit
.eq(in_of
.guard
),
202 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
208 class FPNorm1Single(FPState
):
210 def __init__(self
, width
, id_wid
, single_cycle
=True):
211 FPState
.__init
__(self
, "normalise_1")
212 self
.mod
= FPNorm1ModSingle(width
)
213 self
.o
= self
.ospec()
214 self
.out_z
= FPNumBase(width
, False)
215 self
.out_roundz
= Signal(reset_less
=True)
218 return self
.mod
.ispec()
221 return self
.mod
.ospec()
223 def setup(self
, m
, i
):
224 """ links module to inputs and outputs
232 class FPNorm1Multi(FPState
):
234 def __init__(self
, width
, id_wid
):
235 FPState
.__init
__(self
, "normalise_1")
236 self
.mod
= FPNorm1ModMulti(width
)
237 self
.stb
= Signal(reset_less
=True)
238 self
.ack
= Signal(reset
=0, reset_less
=True)
239 self
.out_norm
= Signal(reset_less
=True)
240 self
.in_accept
= Signal(reset_less
=True)
241 self
.temp_z
= FPNumBase(width
)
242 self
.temp_of
= Overflow()
243 self
.out_z
= FPNumBase(width
)
244 self
.out_roundz
= Signal(reset_less
=True)
246 def setup(self
, m
, in_z
, in_of
, norm_stb
):
247 """ links module to inputs and outputs
249 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
250 self
.in_accept
, self
.temp_z
, self
.temp_of
,
251 self
.out_z
, self
.out_norm
)
253 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
254 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
257 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
258 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
259 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
260 with m
.If(self
.out_norm
):
261 with m
.If(self
.in_accept
):
266 m
.d
.sync
+= self
.ack
.eq(0)
268 # normalisation not required (or done).
270 m
.d
.sync
+= self
.ack
.eq(1)
271 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)