1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Mux
, Elaboratable
6 from nmigen
.cli
import main
, verilog
9 from ieee754
.fpcommon
.fpbase
import (Overflow
, OverflowMod
,
10 FPNumBase
, FPNumBaseRecord
)
11 from ieee754
.fpcommon
.fpbase
import MultiShiftRMerge
12 from ieee754
.fpcommon
.fpbase
import FPState
13 from ieee754
.fpcommon
.getop
import FPPipeContext
14 from ieee754
.fpcommon
.msbhigh
import FPMSBHigh
15 from .postcalc
import FPAddStage1Data
20 def __init__(self
, pspec
):
22 self
.roundz
= Signal(reset_less
=True, name
="norm1_roundz")
23 self
.z
= FPNumBaseRecord(width
, False)
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
30 ret
= [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
31 self
.roundz
.eq(i
.roundz
), self
.ctx
.eq(i
.ctx
)]
35 class FPNorm1ModSingle(Elaboratable
):
37 def __init__(self
, pspec
, e_extra
=False):
39 self
.e_extra
= e_extra
44 return FPAddStage1Data(self
.pspec
, e_extra
=self
.e_extra
)
47 return FPNorm1Data(self
.pspec
)
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 of
= OverflowMod("norm1of_")
63 #m.submodules.norm1_out_z = self.o.z
64 m
.submodules
.norm1_out_overflow
= of
65 #m.submodules.norm1_in_z = self.i.z
66 #m.submodules.norm1_in_overflow = self.i.of
69 i
.of
.guard
.name
= "norm1_i_of_guard"
70 i
.of
.round_bit
.name
= "norm1_i_of_roundbit"
71 i
.of
.sticky
.name
= "norm1_i_of_sticky"
72 i
.of
.m0
.name
= "norm1_i_of_m0"
73 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
74 #m.submodules.norm1_insel_overflow = iof = OverflowMod("iof")
76 espec
= (len(insel_z
.e
), True)
77 mwid
= self
.o
.z
.m_width
+2
79 ediff_n126
= Signal(espec
, reset_less
=True)
80 msr
= MultiShiftRMerge(mwid
+2, espec
)
81 m
.submodules
.multishift_r
= msr
83 msb
= FPMSBHigh(mwid
, espec
[0], True)
84 m
.submodules
.norm_msb
= msb
86 m
.d
.comb
+= i
.eq(self
.i
)
87 # initialise out from in (overridden below)
88 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
89 m
.d
.comb
+= Overflow
.eq(of
, i
.of
)
90 # normalisation increase/decrease conditions
91 decrease
= Signal(reset_less
=True)
92 increase
= Signal(reset_less
=True)
93 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
94 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
96 with m
.If(~self
.i
.out_do_z
):
98 # make sure that the amount to decrease by does NOT
99 # go below the minimum non-INF/NaN exponent
100 temp_m
= Signal(mwid
+1, reset_less
=True)
101 m
.d
.comb
+= msb
.limclz
.eq(insel_z
.exp_sub_n126
)
103 # cat round and guard bits back into the mantissa
104 msb
.m_in
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
106 msb
.e_in
.eq(insel_z
.e
),
107 self
.o
.z
.e
.eq(msb
.e_out
),
108 self
.o
.z
.m
.eq(msb
.m_out
[3:]), # exclude bits 0&1
109 of
.m0
.eq(msb
.m_out
[3]), # copy of mantissa[0]
110 # overflow in bits 0..1: got shifted too (leave sticky)
111 of
.guard
.eq(msb
.m_out
[2]), # guard
112 of
.round_bit
.eq(msb
.m_out
[1]), # round
115 with m
.Elif(increase
):
116 temp_m
= Signal(mwid
+1, reset_less
=True)
118 temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
120 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
121 # connect multi-shifter to inp/out mantissa (and ediff)
123 msr
.diff
.eq(ediff_n126
),
124 self
.o
.z
.m
.eq(msr
.m
[3:]),
125 of
.m0
.eq(msr
.m
[3]), # copy of mantissa[0]
126 # overflow in bits 0..1: got shifted too (leave sticky)
127 of
.guard
.eq(msr
.m
[2]), # guard
128 of
.round_bit
.eq(msr
.m
[1]), # round
129 of
.sticky
.eq(msr
.m
[0]), # sticky
130 self
.o
.z
.e
.eq(insel_z
.e
+ ediff_n126
),
133 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz_out
)
134 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
135 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
136 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
141 class FPNorm1ModMulti
:
143 def __init__(self
, pspec
, single_cycle
=True):
145 self
.in_select
= Signal(reset_less
=True)
146 self
.in_z
= FPNumBase(width
, False)
147 self
.in_of
= Overflow()
148 self
.temp_z
= FPNumBase(width
, False)
149 self
.temp_of
= Overflow()
150 self
.out_z
= FPNumBase(width
, False)
151 self
.out_of
= Overflow()
153 def elaborate(self
, platform
):
156 m
.submodules
.norm1_out_z
= self
.out_z
157 m
.submodules
.norm1_out_overflow
= self
.out_of
158 m
.submodules
.norm1_temp_z
= self
.temp_z
159 m
.submodules
.norm1_temp_of
= self
.temp_of
160 m
.submodules
.norm1_in_z
= self
.in_z
161 m
.submodules
.norm1_in_overflow
= self
.in_of
163 in_z
= FPNumBase(self
.width
, False)
165 m
.submodules
.norm1_insel_z
= in_z
166 m
.submodules
.norm1_insel_overflow
= in_of
168 # select which of temp or in z/of to use
169 with m
.If(self
.in_select
):
170 m
.d
.comb
+= in_z
.eq(self
.in_z
)
171 m
.d
.comb
+= in_of
.eq(self
.in_of
)
173 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
174 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
175 # initialise out from in (overridden below)
176 m
.d
.comb
+= self
.out_z
.eq(in_z
)
177 m
.d
.comb
+= self
.out_of
.eq(in_of
)
178 # normalisation increase/decrease conditions
179 decrease
= Signal(reset_less
=True)
180 increase
= Signal(reset_less
=True)
181 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
182 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
183 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
187 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
188 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
189 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
190 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
191 self
.out_of
.round_bit
.eq(0), # reset round bit
192 self
.out_of
.m0
.eq(in_of
.guard
),
195 with m
.Elif(increase
):
197 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
198 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
199 self
.out_of
.guard
.eq(in_z
.m
[0]),
200 self
.out_of
.m0
.eq(in_z
.m
[1]),
201 self
.out_of
.round_bit
.eq(in_of
.guard
),
202 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
208 class FPNorm1Single(FPState
):
210 def __init__(self
, width
, id_wid
, single_cycle
=True):
211 FPState
.__init
__(self
, "normalise_1")
212 self
.mod
= FPNorm1ModSingle(width
)
213 self
.o
= self
.ospec()
214 self
.out_z
= FPNumBase(width
, False)
215 self
.out_roundz
= Signal(reset_less
=True)
218 return self
.mod
.ispec()
221 return self
.mod
.ospec()
223 def setup(self
, m
, i
):
224 """ links module to inputs and outputs
232 class FPNorm1Multi(FPState
):
234 def __init__(self
, width
, id_wid
):
235 FPState
.__init
__(self
, "normalise_1")
236 self
.mod
= FPNorm1ModMulti(width
)
237 self
.stb
= Signal(reset_less
=True)
238 self
.ack
= Signal(reset
=0, reset_less
=True)
239 self
.out_norm
= Signal(reset_less
=True)
240 self
.in_accept
= Signal(reset_less
=True)
241 self
.temp_z
= FPNumBase(width
)
242 self
.temp_of
= Overflow()
243 self
.out_z
= FPNumBase(width
)
244 self
.out_roundz
= Signal(reset_less
=True)
246 def setup(self
, m
, in_z
, in_of
, norm_stb
):
247 """ links module to inputs and outputs
249 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
250 self
.in_accept
, self
.temp_z
, self
.temp_of
,
251 self
.out_z
, self
.out_norm
)
253 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
254 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
257 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
258 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
259 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
260 with m
.If(self
.out_norm
):
261 with m
.If(self
.in_accept
):
266 m
.d
.sync
+= self
.ack
.eq(0)
268 # normalisation not required (or done).
270 m
.d
.sync
+= self
.ack
.eq(1)
271 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)