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
, pspec
):
21 self
.roundz
= Signal(reset_less
=True, name
="norm1_roundz")
22 self
.z
= FPNumBaseRecord(width
, False)
23 self
.out_do_z
= Signal(reset_less
=True)
24 self
.oz
= Signal(width
, reset_less
=True)
25 self
.ctx
= FPPipeContext(pspec
)
26 self
.muxid
= self
.ctx
.muxid
29 ret
= [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
30 self
.roundz
.eq(i
.roundz
), self
.ctx
.eq(i
.ctx
)]
34 class FPNorm1ModSingle(Elaboratable
):
36 def __init__(self
, pspec
, e_extra
=False):
38 self
.e_extra
= e_extra
43 return FPAddStage1Data(self
.pspec
, e_extra
=self
.e_extra
)
46 return FPNorm1Data(self
.pspec
)
48 def setup(self
, m
, i
):
49 """ links module to inputs and outputs
51 m
.submodules
.normalise_1
= self
52 m
.d
.comb
+= self
.i
.eq(i
)
57 def elaborate(self
, platform
):
60 mwid
= self
.o
.z
.m_width
+2
61 pe
= PriorityEncoder(mwid
)
62 m
.submodules
.norm_pe
= pe
65 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz
)
67 #m.submodules.norm1_out_z = self.o.z
68 #m.submodules.norm1_out_overflow = of
69 #m.submodules.norm1_in_z = self.i.z
70 #m.submodules.norm1_in_overflow = self.i.of
73 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
74 #m.submodules.norm1_insel_overflow = i.of
76 espec
= (len(insel_z
.e
), True)
77 ediff_n126
= Signal(espec
, reset_less
=True)
78 msr
= MultiShiftRMerge(mwid
+2, espec
)
79 m
.submodules
.multishift_r
= msr
81 m
.d
.comb
+= i
.eq(self
.i
)
82 # initialise out from in (overridden below)
83 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
84 m
.d
.comb
+= of
.eq(i
.of
)
85 # normalisation increase/decrease conditions
86 decrease
= Signal(reset_less
=True)
87 increase
= Signal(reset_less
=True)
88 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
89 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
91 with m
.If(~self
.i
.out_do_z
):
93 # *sigh* not entirely obvious: count leading zeros (clz)
94 # with a PriorityEncoder: to find from the MSB
95 # we reverse the order of the bits.
96 temp_m
= Signal(mwid
, reset_less
=True)
97 temp_s
= Signal(mwid
+1, reset_less
=True)
98 clz
= Signal((len(insel_z
.e
), True), reset_less
=True)
99 # make sure that the amount to decrease by does NOT
100 # go below the minimum non-INF/NaN exponent
101 limclz
= Mux(insel_z
.exp_sub_n126
> pe
.o
, pe
.o
,
102 insel_z
.exp_sub_n126
)
104 # cat round and guard bits back into the mantissa
105 temp_m
.eq(Cat(i
.of
.round_bit
, i
.of
.guard
, insel_z
.m
)),
106 pe
.i
.eq(temp_m
[::-1]), # inverted
107 clz
.eq(limclz
), # count zeros from MSB down
108 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
109 self
.o
.z
.e
.eq(insel_z
.e
- clz
), # DECREASE exponent
110 self
.o
.z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
111 of
.m0
.eq(temp_s
[2]), # copy of mantissa[0]
112 # overflow in bits 0..1: got shifted too (leave sticky)
113 of
.guard
.eq(temp_s
[1]), # guard
114 of
.round_bit
.eq(temp_s
[0]), # round
117 with m
.Elif(increase
):
118 temp_m
= Signal(mwid
+1, reset_less
=True)
120 temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
122 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
123 # connect multi-shifter to inp/out mantissa (and ediff)
125 msr
.diff
.eq(ediff_n126
),
126 self
.o
.z
.m
.eq(msr
.m
[3:]),
127 of
.m0
.eq(msr
.m
[3]), # copy of mantissa[0]
128 # overflow in bits 0..1: got shifted too (leave sticky)
129 of
.guard
.eq(msr
.m
[2]), # guard
130 of
.round_bit
.eq(msr
.m
[1]), # round
131 of
.sticky
.eq(msr
.m
[0]), # sticky
132 self
.o
.z
.e
.eq(insel_z
.e
+ ediff_n126
),
135 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
136 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
137 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
142 class FPNorm1ModMulti
:
144 def __init__(self
, pspec
, single_cycle
=True):
146 self
.in_select
= Signal(reset_less
=True)
147 self
.in_z
= FPNumBase(width
, False)
148 self
.in_of
= Overflow()
149 self
.temp_z
= FPNumBase(width
, False)
150 self
.temp_of
= Overflow()
151 self
.out_z
= FPNumBase(width
, False)
152 self
.out_of
= Overflow()
154 def elaborate(self
, platform
):
157 m
.submodules
.norm1_out_z
= self
.out_z
158 m
.submodules
.norm1_out_overflow
= self
.out_of
159 m
.submodules
.norm1_temp_z
= self
.temp_z
160 m
.submodules
.norm1_temp_of
= self
.temp_of
161 m
.submodules
.norm1_in_z
= self
.in_z
162 m
.submodules
.norm1_in_overflow
= self
.in_of
164 in_z
= FPNumBase(self
.width
, False)
166 m
.submodules
.norm1_insel_z
= in_z
167 m
.submodules
.norm1_insel_overflow
= in_of
169 # select which of temp or in z/of to use
170 with m
.If(self
.in_select
):
171 m
.d
.comb
+= in_z
.eq(self
.in_z
)
172 m
.d
.comb
+= in_of
.eq(self
.in_of
)
174 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
175 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
176 # initialise out from in (overridden below)
177 m
.d
.comb
+= self
.out_z
.eq(in_z
)
178 m
.d
.comb
+= self
.out_of
.eq(in_of
)
179 # normalisation increase/decrease conditions
180 decrease
= Signal(reset_less
=True)
181 increase
= Signal(reset_less
=True)
182 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
183 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
184 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
188 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
189 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
190 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
191 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
192 self
.out_of
.round_bit
.eq(0), # reset round bit
193 self
.out_of
.m0
.eq(in_of
.guard
),
196 with m
.Elif(increase
):
198 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
199 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
200 self
.out_of
.guard
.eq(in_z
.m
[0]),
201 self
.out_of
.m0
.eq(in_z
.m
[1]),
202 self
.out_of
.round_bit
.eq(in_of
.guard
),
203 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
209 class FPNorm1Single(FPState
):
211 def __init__(self
, width
, id_wid
, single_cycle
=True):
212 FPState
.__init
__(self
, "normalise_1")
213 self
.mod
= FPNorm1ModSingle(width
)
214 self
.o
= self
.ospec()
215 self
.out_z
= FPNumBase(width
, False)
216 self
.out_roundz
= Signal(reset_less
=True)
219 return self
.mod
.ispec()
222 return self
.mod
.ospec()
224 def setup(self
, m
, i
):
225 """ links module to inputs and outputs
233 class FPNorm1Multi(FPState
):
235 def __init__(self
, width
, id_wid
):
236 FPState
.__init
__(self
, "normalise_1")
237 self
.mod
= FPNorm1ModMulti(width
)
238 self
.stb
= Signal(reset_less
=True)
239 self
.ack
= Signal(reset
=0, reset_less
=True)
240 self
.out_norm
= Signal(reset_less
=True)
241 self
.in_accept
= Signal(reset_less
=True)
242 self
.temp_z
= FPNumBase(width
)
243 self
.temp_of
= Overflow()
244 self
.out_z
= FPNumBase(width
)
245 self
.out_roundz
= Signal(reset_less
=True)
247 def setup(self
, m
, in_z
, in_of
, norm_stb
):
248 """ links module to inputs and outputs
250 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
251 self
.in_accept
, self
.temp_z
, self
.temp_of
,
252 self
.out_z
, self
.out_norm
)
254 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
255 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
258 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
259 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
260 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
261 with m
.If(self
.out_norm
):
262 with m
.If(self
.in_accept
):
267 m
.d
.sync
+= self
.ack
.eq(0)
269 # normalisation not required (or done).
271 m
.d
.sync
+= self
.ack
.eq(1)
272 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)