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
.lib
.coding
import PriorityEncoder
7 from nmigen
.cli
import main
, verilog
10 from ieee754
.fpcommon
.fpbase
import Overflow
, FPNumBase
, FPNumBaseRecord
11 from ieee754
.fpcommon
.fpbase
import MultiShiftRMerge
12 from ieee754
.fpcommon
.fpbase
import FPState
13 from .postcalc
import FPAddStage1Data
18 def __init__(self
, width
, id_wid
, op_wid
=None):
19 self
.roundz
= Signal(reset_less
=True, name
="norm1_roundz")
20 self
.z
= FPNumBaseRecord(width
, False)
21 self
.out_do_z
= Signal(reset_less
=True)
22 self
.oz
= Signal(width
, reset_less
=True)
23 self
.mid
= Signal(id_wid
, reset_less
=True)
26 self
.op
= Signal(op_wid
, reset_less
=True) # operand
29 ret
= [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
30 self
.roundz
.eq(i
.roundz
), self
.mid
.eq(i
.mid
)]
32 ret
.append(self
.op
.eq(i
.op
))
36 class FPNorm1ModSingle(Elaboratable
):
38 def __init__(self
, width
, id_wid
, op_wid
=None):
46 return FPAddStage1Data(self
.width
, self
.id_wid
, self
.op_wid
)
49 return FPNorm1Data(self
.width
, self
.id_wid
, self
.op_wid
)
51 def setup(self
, m
, i
):
52 """ links module to inputs and outputs
54 m
.submodules
.normalise_1
= self
55 m
.d
.comb
+= self
.i
.eq(i
)
60 def elaborate(self
, platform
):
63 mwid
= self
.o
.z
.m_width
+2
64 pe
= PriorityEncoder(mwid
)
65 m
.submodules
.norm_pe
= pe
68 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz
)
70 #m.submodules.norm1_out_z = self.o.z
71 #m.submodules.norm1_out_overflow = of
72 #m.submodules.norm1_in_z = self.i.z
73 #m.submodules.norm1_in_overflow = self.i.of
76 m
.submodules
.norm1_insel_z
= insel_z
= FPNumBase(i
.z
)
77 #m.submodules.norm1_insel_overflow = i.of
79 espec
= (len(insel_z
.e
), True)
80 ediff_n126
= Signal(espec
, reset_less
=True)
81 msr
= MultiShiftRMerge(mwid
+2, espec
)
82 m
.submodules
.multishift_r
= msr
84 m
.d
.comb
+= i
.eq(self
.i
)
85 # initialise out from in (overridden below)
86 m
.d
.comb
+= self
.o
.z
.eq(insel_z
)
87 m
.d
.comb
+= of
.eq(i
.of
)
88 # normalisation increase/decrease conditions
89 decrease
= Signal(reset_less
=True)
90 increase
= Signal(reset_less
=True)
91 m
.d
.comb
+= decrease
.eq(insel_z
.m_msbzero
& insel_z
.exp_gt_n126
)
92 m
.d
.comb
+= increase
.eq(insel_z
.exp_lt_n126
)
94 with m
.If(~self
.i
.out_do_z
):
96 # *sigh* not entirely obvious: count leading zeros (clz)
97 # with a PriorityEncoder: to find from the MSB
98 # we reverse the order of the bits.
99 temp_m
= Signal(mwid
, reset_less
=True)
100 temp_s
= Signal(mwid
+1, reset_less
=True)
101 clz
= Signal((len(insel_z
.e
), True), reset_less
=True)
102 # make sure that the amount to decrease by does NOT
103 # go below the minimum non-INF/NaN exponent
104 limclz
= Mux(insel_z
.exp_sub_n126
> pe
.o
, pe
.o
,
105 insel_z
.exp_sub_n126
)
107 # cat round and guard bits back into the mantissa
108 temp_m
.eq(Cat(i
.of
.round_bit
, i
.of
.guard
, insel_z
.m
)),
109 pe
.i
.eq(temp_m
[::-1]), # inverted
110 clz
.eq(limclz
), # count zeros from MSB down
111 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
112 self
.o
.z
.e
.eq(insel_z
.e
- clz
), # DECREASE exponent
113 self
.o
.z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
114 of
.m0
.eq(temp_s
[2]), # copy of mantissa[0]
115 # overflow in bits 0..1: got shifted too (leave sticky)
116 of
.guard
.eq(temp_s
[1]), # guard
117 of
.round_bit
.eq(temp_s
[0]), # round
120 with m
.Elif(increase
):
121 temp_m
= Signal(mwid
+1, reset_less
=True)
123 temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
125 ediff_n126
.eq(insel_z
.fp
.N126
- insel_z
.e
),
126 # connect multi-shifter to inp/out mantissa (and ediff)
128 msr
.diff
.eq(ediff_n126
),
129 self
.o
.z
.m
.eq(msr
.m
[3:]),
130 of
.m0
.eq(msr
.m
[3]), # copy of mantissa[0]
131 # overflow in bits 0..1: got shifted too (leave sticky)
132 of
.guard
.eq(msr
.m
[2]), # guard
133 of
.round_bit
.eq(msr
.m
[1]), # round
134 of
.sticky
.eq(msr
.m
[0]), # sticky
135 self
.o
.z
.e
.eq(insel_z
.e
+ ediff_n126
),
138 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
139 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
140 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
145 class FPNorm1ModMulti
:
147 def __init__(self
, width
, single_cycle
=True):
149 self
.in_select
= Signal(reset_less
=True)
150 self
.in_z
= FPNumBase(width
, False)
151 self
.in_of
= Overflow()
152 self
.temp_z
= FPNumBase(width
, False)
153 self
.temp_of
= Overflow()
154 self
.out_z
= FPNumBase(width
, False)
155 self
.out_of
= Overflow()
157 def elaborate(self
, platform
):
160 m
.submodules
.norm1_out_z
= self
.out_z
161 m
.submodules
.norm1_out_overflow
= self
.out_of
162 m
.submodules
.norm1_temp_z
= self
.temp_z
163 m
.submodules
.norm1_temp_of
= self
.temp_of
164 m
.submodules
.norm1_in_z
= self
.in_z
165 m
.submodules
.norm1_in_overflow
= self
.in_of
167 in_z
= FPNumBase(self
.width
, False)
169 m
.submodules
.norm1_insel_z
= in_z
170 m
.submodules
.norm1_insel_overflow
= in_of
172 # select which of temp or in z/of to use
173 with m
.If(self
.in_select
):
174 m
.d
.comb
+= in_z
.eq(self
.in_z
)
175 m
.d
.comb
+= in_of
.eq(self
.in_of
)
177 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
178 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
179 # initialise out from in (overridden below)
180 m
.d
.comb
+= self
.out_z
.eq(in_z
)
181 m
.d
.comb
+= self
.out_of
.eq(in_of
)
182 # normalisation increase/decrease conditions
183 decrease
= Signal(reset_less
=True)
184 increase
= Signal(reset_less
=True)
185 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
186 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
187 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
191 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
192 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
193 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
194 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
195 self
.out_of
.round_bit
.eq(0), # reset round bit
196 self
.out_of
.m0
.eq(in_of
.guard
),
199 with m
.Elif(increase
):
201 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
202 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
203 self
.out_of
.guard
.eq(in_z
.m
[0]),
204 self
.out_of
.m0
.eq(in_z
.m
[1]),
205 self
.out_of
.round_bit
.eq(in_of
.guard
),
206 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
212 class FPNorm1Single(FPState
):
214 def __init__(self
, width
, id_wid
, single_cycle
=True):
215 FPState
.__init
__(self
, "normalise_1")
216 self
.mod
= FPNorm1ModSingle(width
)
217 self
.o
= self
.ospec()
218 self
.out_z
= FPNumBase(width
, False)
219 self
.out_roundz
= Signal(reset_less
=True)
222 return self
.mod
.ispec()
225 return self
.mod
.ospec()
227 def setup(self
, m
, i
):
228 """ links module to inputs and outputs
236 class FPNorm1Multi(FPState
):
238 def __init__(self
, width
, id_wid
):
239 FPState
.__init
__(self
, "normalise_1")
240 self
.mod
= FPNorm1ModMulti(width
)
241 self
.stb
= Signal(reset_less
=True)
242 self
.ack
= Signal(reset
=0, reset_less
=True)
243 self
.out_norm
= Signal(reset_less
=True)
244 self
.in_accept
= Signal(reset_less
=True)
245 self
.temp_z
= FPNumBase(width
)
246 self
.temp_of
= Overflow()
247 self
.out_z
= FPNumBase(width
)
248 self
.out_roundz
= Signal(reset_less
=True)
250 def setup(self
, m
, in_z
, in_of
, norm_stb
):
251 """ links module to inputs and outputs
253 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
254 self
.in_accept
, self
.temp_z
, self
.temp_of
,
255 self
.out_z
, self
.out_norm
)
257 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
258 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
261 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
262 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
263 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
264 with m
.If(self
.out_norm
):
265 with m
.If(self
.in_accept
):
270 m
.d
.sync
+= self
.ack
.eq(0)
272 # normalisation not required (or done).
274 m
.d
.sync
+= self
.ack
.eq(1)
275 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)