1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
7 from nmutil
.pipemodbase
import PipeModBase
8 from ieee754
.fpcommon
.fpbase
import (FPRoundingMode
, Overflow
, OverflowMod
,
9 FPNumBase
, FPNumBaseRecord
, FPFormat
)
10 from ieee754
.fpcommon
.fpbase
import FPState
11 from ieee754
.fpcommon
.getop
import FPPipeContext
12 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
13 from ieee754
.fpcommon
.exphigh
import FPEXPHigh
14 from ieee754
.fpcommon
.postcalc
import FPPostCalcData
19 def __init__(self
, pspec
):
21 self
.roundz
= Signal(reset_less
=True, name
="norm1_roundz")
22 self
.z
= FPNumBaseRecord(m_extra
=False, name
="z",
23 fpformat
=FPFormat
.from_pspec(pspec
))
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
29 self
.rm
= Signal(FPRoundingMode
, reset
=FPRoundingMode
.DEFAULT
)
33 ret
= [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
34 self
.roundz
.eq(i
.roundz
), self
.ctx
.eq(i
.ctx
), self
.rm
.eq(i
.rm
)]
38 class FPNorm1ModSingle(PipeModBase
):
40 def __init__(self
, pspec
, e_extra
=False):
41 self
.e_extra
= e_extra
42 super().__init
__(pspec
, "normalise_1")
45 return FPPostCalcData(self
.pspec
, e_extra
=self
.e_extra
)
48 return FPNorm1Data(self
.pspec
)
50 def elaborate(self
, platform
):
53 m
.submodules
.norm1_out_overflow
= of
= OverflowMod("norm1of_")
56 i
.of
.guard
.name
= "norm1_i_of_guard"
57 i
.of
.round_bit
.name
= "norm1_i_of_roundbit"
58 i
.of
.sticky
.name
= "norm1_i_of_sticky"
59 i
.of
.m0
.name
= "norm1_i_of_m0"
60 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
62 espec
= (len(insel_z
.e
), True)
63 mwid
= self
.o
.z
.m_width
+2
65 msr
= FPEXPHigh(mwid
+2, espec
[0])
66 m
.submodules
.norm_exp
= msr
68 msb
= FPMSBHigh(mwid
+1, espec
[0], True)
69 m
.submodules
.norm_msb
= msb
71 m
.d
.comb
+= i
.eq(self
.i
)
72 # initialise out from in (overridden below)
73 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
74 m
.d
.comb
+= Overflow
.eq(of
, i
.of
)
76 # normalisation increase/decrease conditions
77 decrease
= Signal(reset_less
=True)
78 increase
= Signal(reset_less
=True)
79 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
80 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
82 # concatenate s/r/g with mantissa. (it was easier to do this
83 # than to have the mantissa contain the three extra bits)
84 temp_m
= Signal(mwid
+2, reset_less
=True)
85 m
.d
.comb
+= temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
90 # make sure that the amount to decrease by does NOT
91 # go below the minimum non-INF/NaN exponent
92 m
.d
.comb
+= msb
.limclz
.eq(insel_z
.exp_sub_n126
)
94 # inputs: mantissa and exponent
96 msb
.e_in
.eq(insel_z
.e
),
98 # outputs: mantissa first (s/r/g/m[3:])
99 self
.o
.z
.m
.eq(msb
.m_out
[3:]), # exclude bits 0&1
100 of
.m0
.eq(msb
.m_out
[3]), # copy of mantissa[0]
101 # overflow in bits 0..1: got shifted too (leave sticky)
102 of
.guard
.eq(msb
.m_out
[2]), # guard
103 of
.round_bit
.eq(msb
.m_out
[1]), # round
105 self
.o
.z
.e
.eq(msb
.e_out
),
108 with m
.Elif(increase
):
109 ediff_n126
= Signal(espec
, reset_less
=True)
112 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
113 # connect multi-shifter to inp/out m/e (and ediff)
115 msr
.e_in
.eq(insel_z
.e
),
116 msr
.ediff
.eq(ediff_n126
),
118 # outputs: mantissa first (s/r/g/m[3:])
119 self
.o
.z
.m
.eq(msr
.m_out
[3:]),
120 of
.m0
.eq(msr
.m_out
[3]), # copy of mantissa[0]
121 # overflow in bits 0..2: got shifted too (leave sticky)
122 of
.guard
.eq(msr
.m_out
[2]), # guard
123 of
.round_bit
.eq(msr
.m_out
[1]), # round
124 of
.sticky
.eq(msr
.m_out
[0]), # sticky
126 self
.o
.z
.e
.eq(msr
.e_out
),
129 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz_out
)
130 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
131 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
132 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
133 m
.d
.comb
+= self
.o
.rm
.eq(of
.rm
)
138 class FPNorm1ModMulti
:
140 def __init__(self
, pspec
, 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 # sets to zero when not in normalise_1 state
252 m
.d
.sync
+= self
.ack
.eq(0)
255 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
256 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
257 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
258 with m
.If(self
.out_norm
):
259 with m
.If(self
.in_accept
):
264 m
.d
.sync
+= self
.ack
.eq(0)
266 # normalisation not required (or done).
268 m
.d
.sync
+= self
.ack
.eq(1)
269 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)