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
)
74 # normalisation increase/decrease conditions
75 decrease
= Signal(reset_less
=True)
76 increase
= Signal(reset_less
=True)
77 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
78 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
80 # concatenate s/r/g with mantissa. (it was easier to do this
81 # than to have the mantissa contain the three extra bits)
82 temp_m
= Signal(mwid
+2, reset_less
=True)
83 m
.d
.comb
+= temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
88 # make sure that the amount to decrease by does NOT
89 # go below the minimum non-INF/NaN exponent
90 m
.d
.comb
+= msb
.limclz
.eq(insel_z
.exp_sub_n126
)
92 # inputs: mantissa and exponent
94 msb
.e_in
.eq(insel_z
.e
),
96 # outputs: mantissa first (s/r/g/m[3:])
97 self
.o
.z
.m
.eq(msb
.m_out
[3:]), # exclude bits 0&1
98 of
.m0
.eq(msb
.m_out
[3]), # copy of mantissa[0]
99 # overflow in bits 0..1: got shifted too (leave sticky)
100 of
.guard
.eq(msb
.m_out
[2]), # guard
101 of
.round_bit
.eq(msb
.m_out
[1]), # round
103 self
.o
.z
.e
.eq(msb
.e_out
),
106 with m
.Elif(increase
):
107 ediff_n126
= Signal(espec
, reset_less
=True)
110 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
111 # connect multi-shifter to inp/out m/e (and ediff)
113 msr
.e_in
.eq(insel_z
.e
),
114 msr
.ediff
.eq(ediff_n126
),
116 # outputs: mantissa first (s/r/g/m[3:])
117 self
.o
.z
.m
.eq(msr
.m_out
[3:]),
118 of
.m0
.eq(msr
.m_out
[3]), # copy of mantissa[0]
119 # overflow in bits 0..2: got shifted too (leave sticky)
120 of
.guard
.eq(msr
.m_out
[2]), # guard
121 of
.round_bit
.eq(msr
.m_out
[1]), # round
122 of
.sticky
.eq(msr
.m_out
[0]), # sticky
124 self
.o
.z
.e
.eq(msr
.e_out
),
127 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz_out
)
128 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
129 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
130 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
135 class FPNorm1ModMulti
:
137 def __init__(self
, pspec
, single_cycle
=True):
139 self
.in_select
= Signal(reset_less
=True)
140 self
.in_z
= FPNumBase(width
, False)
141 self
.in_of
= Overflow()
142 self
.temp_z
= FPNumBase(width
, False)
143 self
.temp_of
= Overflow()
144 self
.out_z
= FPNumBase(width
, False)
145 self
.out_of
= Overflow()
147 def elaborate(self
, platform
):
150 m
.submodules
.norm1_out_z
= self
.out_z
151 m
.submodules
.norm1_out_overflow
= self
.out_of
152 m
.submodules
.norm1_temp_z
= self
.temp_z
153 m
.submodules
.norm1_temp_of
= self
.temp_of
154 m
.submodules
.norm1_in_z
= self
.in_z
155 m
.submodules
.norm1_in_overflow
= self
.in_of
157 in_z
= FPNumBase(self
.width
, False)
159 m
.submodules
.norm1_insel_z
= in_z
160 m
.submodules
.norm1_insel_overflow
= in_of
162 # select which of temp or in z/of to use
163 with m
.If(self
.in_select
):
164 m
.d
.comb
+= in_z
.eq(self
.in_z
)
165 m
.d
.comb
+= in_of
.eq(self
.in_of
)
167 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
168 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
169 # initialise out from in (overridden below)
170 m
.d
.comb
+= self
.out_z
.eq(in_z
)
171 m
.d
.comb
+= self
.out_of
.eq(in_of
)
172 # normalisation increase/decrease conditions
173 decrease
= Signal(reset_less
=True)
174 increase
= Signal(reset_less
=True)
175 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
176 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
177 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
181 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
182 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
183 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
184 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
185 self
.out_of
.round_bit
.eq(0), # reset round bit
186 self
.out_of
.m0
.eq(in_of
.guard
),
189 with m
.Elif(increase
):
191 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
192 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
193 self
.out_of
.guard
.eq(in_z
.m
[0]),
194 self
.out_of
.m0
.eq(in_z
.m
[1]),
195 self
.out_of
.round_bit
.eq(in_of
.guard
),
196 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
202 class FPNorm1Single(FPState
):
204 def __init__(self
, width
, id_wid
, single_cycle
=True):
205 FPState
.__init
__(self
, "normalise_1")
206 self
.mod
= FPNorm1ModSingle(width
)
207 self
.o
= self
.ospec()
208 self
.out_z
= FPNumBase(width
, False)
209 self
.out_roundz
= Signal(reset_less
=True)
212 return self
.mod
.ispec()
215 return self
.mod
.ospec()
217 def setup(self
, m
, i
):
218 """ links module to inputs and outputs
226 class FPNorm1Multi(FPState
):
228 def __init__(self
, width
, id_wid
):
229 FPState
.__init
__(self
, "normalise_1")
230 self
.mod
= FPNorm1ModMulti(width
)
231 self
.stb
= Signal(reset_less
=True)
232 self
.ack
= Signal(reset
=0, reset_less
=True)
233 self
.out_norm
= Signal(reset_less
=True)
234 self
.in_accept
= Signal(reset_less
=True)
235 self
.temp_z
= FPNumBase(width
)
236 self
.temp_of
= Overflow()
237 self
.out_z
= FPNumBase(width
)
238 self
.out_roundz
= Signal(reset_less
=True)
240 def setup(self
, m
, in_z
, in_of
, norm_stb
):
241 """ links module to inputs and outputs
243 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
244 self
.in_accept
, self
.temp_z
, self
.temp_of
,
245 self
.out_z
, self
.out_norm
)
247 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
248 # sets to zero when not in normalise_1 state
249 m
.d
.sync
+= self
.ack
.eq(0)
252 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
253 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
254 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
255 with m
.If(self
.out_norm
):
256 with m
.If(self
.in_accept
):
261 m
.d
.sync
+= self
.ack
.eq(0)
263 # normalisation not required (or done).
265 m
.d
.sync
+= self
.ack
.eq(1)
266 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)