1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Mux
, Array
, Const
6 from nmigen
.lib
.coding
import PriorityEncoder
7 from nmigen
.cli
import main
, verilog
10 from fpbase
import FPNumIn
, FPNumOut
, FPOp
, Overflow
, FPBase
, FPNumBase
11 from fpbase
import MultiShiftRMerge
, Trigger
12 from singlepipe
import (ControlBase
, StageChain
, UnbufferedPipeline
,
14 from multipipe
import CombMuxOutPipe
15 from multipipe
import PriorityCombMuxInPipe
17 from fpbase
import FPState
18 from .postcalc
import FPAddStage1Data
23 def __init__(self
, width
, id_wid
):
24 self
.roundz
= Signal(reset_less
=True)
25 self
.z
= FPNumBase(width
, False)
26 self
.out_do_z
= Signal(reset_less
=True)
27 self
.oz
= Signal(width
, reset_less
=True)
28 self
.mid
= Signal(id_wid
, reset_less
=True)
31 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
32 self
.roundz
.eq(i
.roundz
), self
.mid
.eq(i
.mid
)]
35 class FPNorm1ModSingle
:
37 def __init__(self
, width
, id_wid
):
44 return FPAddStage1Data(self
.width
, self
.id_wid
)
47 return FPNorm1Data(self
.width
, self
.id_wid
)
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 mwid
= self
.o
.z
.m_width
+2
62 pe
= PriorityEncoder(mwid
)
63 m
.submodules
.norm_pe
= pe
66 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz
)
68 m
.submodules
.norm1_out_z
= self
.o
.z
69 m
.submodules
.norm1_out_overflow
= of
70 m
.submodules
.norm1_in_z
= self
.i
.z
71 m
.submodules
.norm1_in_overflow
= self
.i
.of
74 m
.submodules
.norm1_insel_z
= i
.z
75 m
.submodules
.norm1_insel_overflow
= i
.of
77 espec
= (len(i
.z
.e
), True)
78 ediff_n126
= Signal(espec
, reset_less
=True)
79 msr
= MultiShiftRMerge(mwid
, espec
)
80 m
.submodules
.multishift_r
= msr
82 m
.d
.comb
+= i
.eq(self
.i
)
83 # initialise out from in (overridden below)
84 m
.d
.comb
+= self
.o
.z
.eq(i
.z
)
85 m
.d
.comb
+= of
.eq(i
.of
)
86 # normalisation increase/decrease conditions
87 decrease
= Signal(reset_less
=True)
88 increase
= Signal(reset_less
=True)
89 m
.d
.comb
+= decrease
.eq(i
.z
.m_msbzero
& i
.z
.exp_gt_n126
)
90 m
.d
.comb
+= increase
.eq(i
.z
.exp_lt_n126
)
92 with m
.If(~self
.i
.out_do_z
):
94 # *sigh* not entirely obvious: count leading zeros (clz)
95 # with a PriorityEncoder: to find from the MSB
96 # we reverse the order of the bits.
97 temp_m
= Signal(mwid
, reset_less
=True)
98 temp_s
= Signal(mwid
+1, reset_less
=True)
99 clz
= Signal((len(i
.z
.e
), True), reset_less
=True)
100 # make sure that the amount to decrease by does NOT
101 # go below the minimum non-INF/NaN exponent
102 limclz
= Mux(i
.z
.exp_sub_n126
> pe
.o
, pe
.o
,
105 # cat round and guard bits back into the mantissa
106 temp_m
.eq(Cat(i
.of
.round_bit
, i
.of
.guard
, i
.z
.m
)),
107 pe
.i
.eq(temp_m
[::-1]), # inverted
108 clz
.eq(limclz
), # count zeros from MSB down
109 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
110 self
.o
.z
.e
.eq(i
.z
.e
- clz
), # DECREASE exponent
111 self
.o
.z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
112 of
.m0
.eq(temp_s
[2]), # copy of mantissa[0]
113 # overflow in bits 0..1: got shifted too (leave sticky)
114 of
.guard
.eq(temp_s
[1]), # guard
115 of
.round_bit
.eq(temp_s
[0]), # round
118 with m
.Elif(increase
):
119 temp_m
= Signal(mwid
+1, reset_less
=True)
121 temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
123 ediff_n126
.eq(i
.z
.N126
- i
.z
.e
),
124 # connect multi-shifter to inp/out mantissa (and ediff)
126 msr
.diff
.eq(ediff_n126
),
127 self
.o
.z
.m
.eq(msr
.m
[3:]),
128 of
.m0
.eq(temp_s
[3]), # copy of mantissa[0]
129 # overflow in bits 0..1: got shifted too (leave sticky)
130 of
.guard
.eq(temp_s
[2]), # guard
131 of
.round_bit
.eq(temp_s
[1]), # round
132 of
.sticky
.eq(temp_s
[0]), # sticky
133 self
.o
.z
.e
.eq(i
.z
.e
+ ediff_n126
),
136 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
137 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
138 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
143 class FPNorm1ModMulti
:
145 def __init__(self
, width
, single_cycle
=True):
147 self
.in_select
= Signal(reset_less
=True)
148 self
.in_z
= FPNumBase(width
, False)
149 self
.in_of
= Overflow()
150 self
.temp_z
= FPNumBase(width
, False)
151 self
.temp_of
= Overflow()
152 self
.out_z
= FPNumBase(width
, False)
153 self
.out_of
= Overflow()
155 def elaborate(self
, platform
):
158 m
.submodules
.norm1_out_z
= self
.out_z
159 m
.submodules
.norm1_out_overflow
= self
.out_of
160 m
.submodules
.norm1_temp_z
= self
.temp_z
161 m
.submodules
.norm1_temp_of
= self
.temp_of
162 m
.submodules
.norm1_in_z
= self
.in_z
163 m
.submodules
.norm1_in_overflow
= self
.in_of
165 in_z
= FPNumBase(self
.width
, False)
167 m
.submodules
.norm1_insel_z
= in_z
168 m
.submodules
.norm1_insel_overflow
= in_of
170 # select which of temp or in z/of to use
171 with m
.If(self
.in_select
):
172 m
.d
.comb
+= in_z
.eq(self
.in_z
)
173 m
.d
.comb
+= in_of
.eq(self
.in_of
)
175 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
176 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
177 # initialise out from in (overridden below)
178 m
.d
.comb
+= self
.out_z
.eq(in_z
)
179 m
.d
.comb
+= self
.out_of
.eq(in_of
)
180 # normalisation increase/decrease conditions
181 decrease
= Signal(reset_less
=True)
182 increase
= Signal(reset_less
=True)
183 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
184 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
185 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
189 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
190 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
191 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
192 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
193 self
.out_of
.round_bit
.eq(0), # reset round bit
194 self
.out_of
.m0
.eq(in_of
.guard
),
197 with m
.Elif(increase
):
199 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
200 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
201 self
.out_of
.guard
.eq(in_z
.m
[0]),
202 self
.out_of
.m0
.eq(in_z
.m
[1]),
203 self
.out_of
.round_bit
.eq(in_of
.guard
),
204 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
210 class FPNorm1Single(FPState
):
212 def __init__(self
, width
, id_wid
, single_cycle
=True):
213 FPState
.__init
__(self
, "normalise_1")
214 self
.mod
= FPNorm1ModSingle(width
)
215 self
.o
= self
.ospec()
216 self
.out_z
= FPNumBase(width
, False)
217 self
.out_roundz
= Signal(reset_less
=True)
220 return self
.mod
.ispec()
223 return self
.mod
.ospec()
225 def setup(self
, m
, i
):
226 """ links module to inputs and outputs
234 class FPNorm1Multi(FPState
):
236 def __init__(self
, width
, id_wid
):
237 FPState
.__init
__(self
, "normalise_1")
238 self
.mod
= FPNorm1ModMulti(width
)
239 self
.stb
= Signal(reset_less
=True)
240 self
.ack
= Signal(reset
=0, reset_less
=True)
241 self
.out_norm
= Signal(reset_less
=True)
242 self
.in_accept
= Signal(reset_less
=True)
243 self
.temp_z
= FPNumBase(width
)
244 self
.temp_of
= Overflow()
245 self
.out_z
= FPNumBase(width
)
246 self
.out_roundz
= Signal(reset_less
=True)
248 def setup(self
, m
, in_z
, in_of
, norm_stb
):
249 """ links module to inputs and outputs
251 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
252 self
.in_accept
, self
.temp_z
, self
.temp_of
,
253 self
.out_z
, self
.out_norm
)
255 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
256 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
259 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
260 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
261 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
262 with m
.If(self
.out_norm
):
263 with m
.If(self
.in_accept
):
268 m
.d
.sync
+= self
.ack
.eq(0)
270 # normalisation not required (or done).
272 m
.d
.sync
+= self
.ack
.eq(1)
273 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)