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
)
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(width
, False, name
="z")
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
28 self
.rm
= Signal(FPRoundingMode
, reset
=FPRoundingMode
.DEFAULT
)
32 ret
= [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
33 self
.roundz
.eq(i
.roundz
), self
.ctx
.eq(i
.ctx
), self
.rm
.eq(i
.rm
)]
37 class FPNorm1ModSingle(PipeModBase
):
39 def __init__(self
, pspec
, e_extra
=False):
40 self
.e_extra
= e_extra
41 super().__init
__(pspec
, "normalise_1")
44 return FPPostCalcData(self
.pspec
, e_extra
=self
.e_extra
)
47 return FPNorm1Data(self
.pspec
)
49 def elaborate(self
, platform
):
52 m
.submodules
.norm1_out_overflow
= of
= OverflowMod("norm1of_")
55 i
.of
.guard
.name
= "norm1_i_of_guard"
56 i
.of
.round_bit
.name
= "norm1_i_of_roundbit"
57 i
.of
.sticky
.name
= "norm1_i_of_sticky"
58 i
.of
.m0
.name
= "norm1_i_of_m0"
59 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
61 espec
= (len(insel_z
.e
), True)
62 mwid
= self
.o
.z
.m_width
+2
64 msr
= FPEXPHigh(mwid
+2, espec
[0])
65 m
.submodules
.norm_exp
= msr
67 msb
= FPMSBHigh(mwid
+1, espec
[0], True)
68 m
.submodules
.norm_msb
= msb
70 m
.d
.comb
+= i
.eq(self
.i
)
71 # initialise out from in (overridden below)
72 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
73 m
.d
.comb
+= Overflow
.eq(of
, i
.of
)
75 # normalisation increase/decrease conditions
76 decrease
= Signal(reset_less
=True)
77 increase
= Signal(reset_less
=True)
78 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
79 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
81 # concatenate s/r/g with mantissa. (it was easier to do this
82 # than to have the mantissa contain the three extra bits)
83 temp_m
= Signal(mwid
+2, reset_less
=True)
84 m
.d
.comb
+= temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
89 # make sure that the amount to decrease by does NOT
90 # go below the minimum non-INF/NaN exponent
91 m
.d
.comb
+= msb
.limclz
.eq(insel_z
.exp_sub_n126
)
93 # inputs: mantissa and exponent
95 msb
.e_in
.eq(insel_z
.e
),
97 # outputs: mantissa first (s/r/g/m[3:])
98 self
.o
.z
.m
.eq(msb
.m_out
[3:]), # exclude bits 0&1
99 of
.m0
.eq(msb
.m_out
[3]), # copy of mantissa[0]
100 # overflow in bits 0..1: got shifted too (leave sticky)
101 of
.guard
.eq(msb
.m_out
[2]), # guard
102 of
.round_bit
.eq(msb
.m_out
[1]), # round
104 self
.o
.z
.e
.eq(msb
.e_out
),
107 with m
.Elif(increase
):
108 ediff_n126
= Signal(espec
, reset_less
=True)
111 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
112 # connect multi-shifter to inp/out m/e (and ediff)
114 msr
.e_in
.eq(insel_z
.e
),
115 msr
.ediff
.eq(ediff_n126
),
117 # outputs: mantissa first (s/r/g/m[3:])
118 self
.o
.z
.m
.eq(msr
.m_out
[3:]),
119 of
.m0
.eq(msr
.m_out
[3]), # copy of mantissa[0]
120 # overflow in bits 0..2: got shifted too (leave sticky)
121 of
.guard
.eq(msr
.m_out
[2]), # guard
122 of
.round_bit
.eq(msr
.m_out
[1]), # round
123 of
.sticky
.eq(msr
.m_out
[0]), # sticky
125 self
.o
.z
.e
.eq(msr
.e_out
),
128 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz_out
)
129 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
130 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
131 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
132 m
.d
.comb
+= self
.o
.rm
.eq(of
.rm
)
137 class FPNorm1ModMulti
:
139 def __init__(self
, pspec
, single_cycle
=True):
141 self
.in_select
= Signal(reset_less
=True)
142 self
.in_z
= FPNumBase(width
, False)
143 self
.in_of
= Overflow()
144 self
.temp_z
= FPNumBase(width
, False)
145 self
.temp_of
= Overflow()
146 self
.out_z
= FPNumBase(width
, False)
147 self
.out_of
= Overflow()
149 def elaborate(self
, platform
):
152 m
.submodules
.norm1_out_z
= self
.out_z
153 m
.submodules
.norm1_out_overflow
= self
.out_of
154 m
.submodules
.norm1_temp_z
= self
.temp_z
155 m
.submodules
.norm1_temp_of
= self
.temp_of
156 m
.submodules
.norm1_in_z
= self
.in_z
157 m
.submodules
.norm1_in_overflow
= self
.in_of
159 in_z
= FPNumBase(self
.width
, False)
161 m
.submodules
.norm1_insel_z
= in_z
162 m
.submodules
.norm1_insel_overflow
= in_of
164 # select which of temp or in z/of to use
165 with m
.If(self
.in_select
):
166 m
.d
.comb
+= in_z
.eq(self
.in_z
)
167 m
.d
.comb
+= in_of
.eq(self
.in_of
)
169 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
170 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
171 # initialise out from in (overridden below)
172 m
.d
.comb
+= self
.out_z
.eq(in_z
)
173 m
.d
.comb
+= self
.out_of
.eq(in_of
)
174 # normalisation increase/decrease conditions
175 decrease
= Signal(reset_less
=True)
176 increase
= Signal(reset_less
=True)
177 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
178 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
179 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
183 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
184 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
185 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
186 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
187 self
.out_of
.round_bit
.eq(0), # reset round bit
188 self
.out_of
.m0
.eq(in_of
.guard
),
191 with m
.Elif(increase
):
193 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
194 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
195 self
.out_of
.guard
.eq(in_z
.m
[0]),
196 self
.out_of
.m0
.eq(in_z
.m
[1]),
197 self
.out_of
.round_bit
.eq(in_of
.guard
),
198 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
204 class FPNorm1Single(FPState
):
206 def __init__(self
, width
, id_wid
, single_cycle
=True):
207 FPState
.__init
__(self
, "normalise_1")
208 self
.mod
= FPNorm1ModSingle(width
)
209 self
.o
= self
.ospec()
210 self
.out_z
= FPNumBase(width
, False)
211 self
.out_roundz
= Signal(reset_less
=True)
214 return self
.mod
.ispec()
217 return self
.mod
.ospec()
219 def setup(self
, m
, i
):
220 """ links module to inputs and outputs
228 class FPNorm1Multi(FPState
):
230 def __init__(self
, width
, id_wid
):
231 FPState
.__init
__(self
, "normalise_1")
232 self
.mod
= FPNorm1ModMulti(width
)
233 self
.stb
= Signal(reset_less
=True)
234 self
.ack
= Signal(reset
=0, reset_less
=True)
235 self
.out_norm
= Signal(reset_less
=True)
236 self
.in_accept
= Signal(reset_less
=True)
237 self
.temp_z
= FPNumBase(width
)
238 self
.temp_of
= Overflow()
239 self
.out_z
= FPNumBase(width
)
240 self
.out_roundz
= Signal(reset_less
=True)
242 def setup(self
, m
, in_z
, in_of
, norm_stb
):
243 """ links module to inputs and outputs
245 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
246 self
.in_accept
, self
.temp_z
, self
.temp_of
,
247 self
.out_z
, self
.out_norm
)
249 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
250 # sets to zero when not in normalise_1 state
251 m
.d
.sync
+= self
.ack
.eq(0)
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
)