1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Mux
6 from nmigen
.cli
import main
, verilog
9 from nmutil
.pipemodbase
import PipeModBase
10 from ieee754
.fpcommon
.fpbase
import (Overflow
, OverflowMod
,
11 FPNumBase
, FPNumBaseRecord
)
12 from ieee754
.fpcommon
.fpbase
import FPState
13 from ieee754
.fpcommon
.getop
import FPPipeContext
14 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
15 from ieee754
.fpcommon
.exphigh
import FPEXPHigh
16 from ieee754
.fpcommon
.postcalc
import FPPostCalcData
21 def __init__(self
, pspec
):
23 self
.roundz
= Signal(reset_less
=True, name
="norm1_roundz")
24 self
.z
= FPNumBaseRecord(width
, False, name
="z")
25 self
.out_do_z
= Signal(reset_less
=True)
26 self
.oz
= Signal(width
, reset_less
=True)
27 self
.ctx
= FPPipeContext(pspec
)
28 self
.muxid
= self
.ctx
.muxid
31 ret
= [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
.ctx
.eq(i
.ctx
)]
36 class FPNorm1ModSingle(PipeModBase
):
38 def __init__(self
, pspec
, e_extra
=False):
39 self
.e_extra
= e_extra
40 super().__init
__(pspec
, "normalise_1")
43 return FPPostCalcData(self
.pspec
, e_extra
=self
.e_extra
)
46 return FPNorm1Data(self
.pspec
)
48 def elaborate(self
, platform
):
51 m
.submodules
.norm1_out_overflow
= of
= OverflowMod("norm1of_")
54 i
.of
.guard
.name
= "norm1_i_of_guard"
55 i
.of
.round_bit
.name
= "norm1_i_of_roundbit"
56 i
.of
.sticky
.name
= "norm1_i_of_sticky"
57 i
.of
.m0
.name
= "norm1_i_of_m0"
58 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
60 espec
= (len(insel_z
.e
), True)
61 mwid
= self
.o
.z
.m_width
+2
63 msr
= FPEXPHigh(mwid
+2, espec
[0])
64 m
.submodules
.norm_exp
= msr
66 msb
= FPMSBHigh(mwid
+1, espec
[0], True)
67 m
.submodules
.norm_msb
= msb
69 m
.d
.comb
+= i
.eq(self
.i
)
70 # initialise out from in (overridden below)
71 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
72 m
.d
.comb
+= Overflow
.eq(of
, i
.of
)
73 with m
.If(~self
.i
.out_do_z
):
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
)
136 class FPNorm1ModMulti
:
138 def __init__(self
, pspec
, single_cycle
=True):
140 self
.in_select
= Signal(reset_less
=True)
141 self
.in_z
= FPNumBase(width
, False)
142 self
.in_of
= Overflow()
143 self
.temp_z
= FPNumBase(width
, False)
144 self
.temp_of
= Overflow()
145 self
.out_z
= FPNumBase(width
, False)
146 self
.out_of
= Overflow()
148 def elaborate(self
, platform
):
151 m
.submodules
.norm1_out_z
= self
.out_z
152 m
.submodules
.norm1_out_overflow
= self
.out_of
153 m
.submodules
.norm1_temp_z
= self
.temp_z
154 m
.submodules
.norm1_temp_of
= self
.temp_of
155 m
.submodules
.norm1_in_z
= self
.in_z
156 m
.submodules
.norm1_in_overflow
= self
.in_of
158 in_z
= FPNumBase(self
.width
, False)
160 m
.submodules
.norm1_insel_z
= in_z
161 m
.submodules
.norm1_insel_overflow
= in_of
163 # select which of temp or in z/of to use
164 with m
.If(self
.in_select
):
165 m
.d
.comb
+= in_z
.eq(self
.in_z
)
166 m
.d
.comb
+= in_of
.eq(self
.in_of
)
168 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
169 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
170 # initialise out from in (overridden below)
171 m
.d
.comb
+= self
.out_z
.eq(in_z
)
172 m
.d
.comb
+= self
.out_of
.eq(in_of
)
173 # normalisation increase/decrease conditions
174 decrease
= Signal(reset_less
=True)
175 increase
= Signal(reset_less
=True)
176 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
177 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
178 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
182 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
183 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
184 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
185 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
186 self
.out_of
.round_bit
.eq(0), # reset round bit
187 self
.out_of
.m0
.eq(in_of
.guard
),
190 with m
.Elif(increase
):
192 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
193 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
194 self
.out_of
.guard
.eq(in_z
.m
[0]),
195 self
.out_of
.m0
.eq(in_z
.m
[1]),
196 self
.out_of
.round_bit
.eq(in_of
.guard
),
197 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
203 class FPNorm1Single(FPState
):
205 def __init__(self
, width
, id_wid
, single_cycle
=True):
206 FPState
.__init
__(self
, "normalise_1")
207 self
.mod
= FPNorm1ModSingle(width
)
208 self
.o
= self
.ospec()
209 self
.out_z
= FPNumBase(width
, False)
210 self
.out_roundz
= Signal(reset_less
=True)
213 return self
.mod
.ispec()
216 return self
.mod
.ospec()
218 def setup(self
, m
, i
):
219 """ links module to inputs and outputs
227 class FPNorm1Multi(FPState
):
229 def __init__(self
, width
, id_wid
):
230 FPState
.__init
__(self
, "normalise_1")
231 self
.mod
= FPNorm1ModMulti(width
)
232 self
.stb
= Signal(reset_less
=True)
233 self
.ack
= Signal(reset
=0, reset_less
=True)
234 self
.out_norm
= Signal(reset_less
=True)
235 self
.in_accept
= Signal(reset_less
=True)
236 self
.temp_z
= FPNumBase(width
)
237 self
.temp_of
= Overflow()
238 self
.out_z
= FPNumBase(width
)
239 self
.out_roundz
= Signal(reset_less
=True)
241 def setup(self
, m
, in_z
, in_of
, norm_stb
):
242 """ links module to inputs and outputs
244 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
245 self
.in_accept
, self
.temp_z
, self
.temp_of
,
246 self
.out_z
, self
.out_norm
)
248 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
249 # sets to zero when not in normalise_1 state
250 m
.d
.sync
+= self
.ack
.eq(0)
253 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
254 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
255 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
256 with m
.If(self
.out_norm
):
257 with m
.If(self
.in_accept
):
262 m
.d
.sync
+= self
.ack
.eq(0)
264 # normalisation not required (or done).
266 m
.d
.sync
+= self
.ack
.eq(1)
267 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)