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 FPModBase
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 FPAddStage1Data
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(FPModBase
):
38 def __init__(self
, pspec
, e_extra
=False):
39 self
.e_extra
= e_extra
40 super().__init
__(pspec
, "normalise_1")
43 return FPAddStage1Data(self
.pspec
, e_extra
=self
.e_extra
)
46 return FPNorm1Data(self
.pspec
)
48 def elaborate(self
, platform
):
51 of
= OverflowMod("norm1of_")
53 #m.submodules.norm1_out_z = self.o.z
54 m
.submodules
.norm1_out_overflow
= of
55 #m.submodules.norm1_in_z = self.i.z
56 #m.submodules.norm1_in_overflow = self.i.of
59 i
.of
.guard
.name
= "norm1_i_of_guard"
60 i
.of
.round_bit
.name
= "norm1_i_of_roundbit"
61 i
.of
.sticky
.name
= "norm1_i_of_sticky"
62 i
.of
.m0
.name
= "norm1_i_of_m0"
63 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
64 #m.submodules.norm1_insel_overflow = iof = OverflowMod("iof")
66 espec
= (len(insel_z
.e
), True)
67 mwid
= self
.o
.z
.m_width
+2
69 msr
= FPEXPHigh(mwid
+2, espec
[0])
70 m
.submodules
.norm_exp
= msr
72 msb
= FPMSBHigh(mwid
+1, espec
[0], True)
73 m
.submodules
.norm_msb
= msb
75 m
.d
.comb
+= i
.eq(self
.i
)
76 # initialise out from in (overridden below)
77 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
78 m
.d
.comb
+= Overflow
.eq(of
, i
.of
)
79 # normalisation increase/decrease conditions
80 decrease
= Signal(reset_less
=True)
81 increase
= Signal(reset_less
=True)
82 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
83 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
85 with m
.If(~self
.i
.out_do_z
):
86 # concatenate s/r/g with mantissa
87 temp_m
= Signal(mwid
+2, reset_less
=True)
88 m
.d
.comb
+= temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
92 # make sure that the amount to decrease by does NOT
93 # go below the minimum non-INF/NaN exponent
94 m
.d
.comb
+= msb
.limclz
.eq(insel_z
.exp_sub_n126
)
96 # inputs: mantissa and exponent
98 msb
.e_in
.eq(insel_z
.e
),
100 # outputs: mantissa first (s/r/g/m[3:])
101 self
.o
.z
.m
.eq(msb
.m_out
[3:]), # exclude bits 0&1
102 of
.m0
.eq(msb
.m_out
[3]), # copy of mantissa[0]
103 # overflow in bits 0..1: got shifted too (leave sticky)
104 of
.guard
.eq(msb
.m_out
[2]), # guard
105 of
.round_bit
.eq(msb
.m_out
[1]), # round
107 self
.o
.z
.e
.eq(msb
.e_out
),
110 with m
.Elif(increase
):
111 ediff_n126
= Signal(espec
, reset_less
=True)
114 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
115 # connect multi-shifter to inp/out m/e (and ediff)
117 msr
.e_in
.eq(insel_z
.e
),
118 msr
.ediff
.eq(ediff_n126
),
120 # outputs: mantissa first (s/r/g/m[3:])
121 self
.o
.z
.m
.eq(msr
.m_out
[3:]),
122 of
.m0
.eq(msr
.m_out
[3]), # copy of mantissa[0]
123 # overflow in bits 0..2: got shifted too (leave sticky)
124 of
.guard
.eq(msr
.m_out
[2]), # guard
125 of
.round_bit
.eq(msr
.m_out
[1]), # round
126 of
.sticky
.eq(msr
.m_out
[0]), # sticky
128 self
.o
.z
.e
.eq(msr
.e_out
),
131 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz_out
)
132 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
133 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
134 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
139 class FPNorm1ModMulti
:
141 def __init__(self
, pspec
, single_cycle
=True):
143 self
.in_select
= Signal(reset_less
=True)
144 self
.in_z
= FPNumBase(width
, False)
145 self
.in_of
= Overflow()
146 self
.temp_z
= FPNumBase(width
, False)
147 self
.temp_of
= Overflow()
148 self
.out_z
= FPNumBase(width
, False)
149 self
.out_of
= Overflow()
151 def elaborate(self
, platform
):
154 m
.submodules
.norm1_out_z
= self
.out_z
155 m
.submodules
.norm1_out_overflow
= self
.out_of
156 m
.submodules
.norm1_temp_z
= self
.temp_z
157 m
.submodules
.norm1_temp_of
= self
.temp_of
158 m
.submodules
.norm1_in_z
= self
.in_z
159 m
.submodules
.norm1_in_overflow
= self
.in_of
161 in_z
= FPNumBase(self
.width
, False)
163 m
.submodules
.norm1_insel_z
= in_z
164 m
.submodules
.norm1_insel_overflow
= in_of
166 # select which of temp or in z/of to use
167 with m
.If(self
.in_select
):
168 m
.d
.comb
+= in_z
.eq(self
.in_z
)
169 m
.d
.comb
+= in_of
.eq(self
.in_of
)
171 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
172 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
173 # initialise out from in (overridden below)
174 m
.d
.comb
+= self
.out_z
.eq(in_z
)
175 m
.d
.comb
+= self
.out_of
.eq(in_of
)
176 # normalisation increase/decrease conditions
177 decrease
= Signal(reset_less
=True)
178 increase
= Signal(reset_less
=True)
179 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
180 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
181 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
185 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
186 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
187 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
188 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
189 self
.out_of
.round_bit
.eq(0), # reset round bit
190 self
.out_of
.m0
.eq(in_of
.guard
),
193 with m
.Elif(increase
):
195 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
196 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
197 self
.out_of
.guard
.eq(in_z
.m
[0]),
198 self
.out_of
.m0
.eq(in_z
.m
[1]),
199 self
.out_of
.round_bit
.eq(in_of
.guard
),
200 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
206 class FPNorm1Single(FPState
):
208 def __init__(self
, width
, id_wid
, single_cycle
=True):
209 FPState
.__init
__(self
, "normalise_1")
210 self
.mod
= FPNorm1ModSingle(width
)
211 self
.o
= self
.ospec()
212 self
.out_z
= FPNumBase(width
, False)
213 self
.out_roundz
= Signal(reset_less
=True)
216 return self
.mod
.ispec()
219 return self
.mod
.ospec()
221 def setup(self
, m
, i
):
222 """ links module to inputs and outputs
230 class FPNorm1Multi(FPState
):
232 def __init__(self
, width
, id_wid
):
233 FPState
.__init
__(self
, "normalise_1")
234 self
.mod
= FPNorm1ModMulti(width
)
235 self
.stb
= Signal(reset_less
=True)
236 self
.ack
= Signal(reset
=0, reset_less
=True)
237 self
.out_norm
= Signal(reset_less
=True)
238 self
.in_accept
= Signal(reset_less
=True)
239 self
.temp_z
= FPNumBase(width
)
240 self
.temp_of
= Overflow()
241 self
.out_z
= FPNumBase(width
)
242 self
.out_roundz
= Signal(reset_less
=True)
244 def setup(self
, m
, in_z
, in_of
, norm_stb
):
245 """ links module to inputs and outputs
247 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
248 self
.in_accept
, self
.temp_z
, self
.temp_of
,
249 self
.out_z
, self
.out_norm
)
251 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
252 # sets to zero when not in normalise_1 state
253 m
.d
.sync
+= self
.ack
.eq(0)
256 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
257 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
258 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
259 with m
.If(self
.out_norm
):
260 with m
.If(self
.in_accept
):
265 m
.d
.sync
+= self
.ack
.eq(0)
267 # normalisation not required (or done).
269 m
.d
.sync
+= self
.ack
.eq(1)
270 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)