separate denormalisation module and use it
[ieee754fpu.git] / src / add / nmigen_add_experiment.py
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
3 # 2013-12-12
4
5 from nmigen import Module, Signal, Cat
6 from nmigen.cli import main, verilog
7
8 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
9
10
11 class FPState(FPBase):
12 def __init__(self, state_from):
13 self.state_from = state_from
14
15 def set_inputs(self, inputs):
16 self.inputs = inputs
17 for k,v in inputs.items():
18 setattr(self, k, v)
19
20 def set_outputs(self, outputs):
21 self.outputs = outputs
22 for k,v in outputs.items():
23 setattr(self, k, v)
24
25
26 class FPGetOpA(FPState):
27 """ gets operand a
28 """
29
30 def __init__(self, in_a, width):
31 FPState.__init__(self, "get_a")
32 self.in_a = in_a
33 self.a = FPNumIn(in_a, width)
34
35 def action(self, m):
36 self.get_op(m, self.in_a, self.a, "get_b")
37
38
39 class FPGetOpB(FPState):
40 """ gets operand b
41 """
42
43 def action(self, m):
44 self.get_op(m, self.in_b, self.b, "special_cases")
45
46
47 class FPAddSpecialCasesMod:
48 """ special cases: NaNs, infs, zeros, denormalised
49 NOTE: some of these are unique to add. see "Special Operations"
50 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
51 """
52
53 def __init__(self, width):
54 self.in_a = FPNumBase(width)
55 self.in_b = FPNumBase(width)
56 self.out_z = FPNumOut(width, False)
57 self.out_do_z = Signal(reset_less=True)
58
59 def setup(self, m, in_a, in_b, out_z, out_do_z):
60 """ links module to inputs and outputs
61 """
62 m.d.comb += self.in_a.copy(in_a)
63 m.d.comb += self.in_b.copy(in_b)
64 m.d.comb += out_z.v.eq(self.out_z.v)
65 m.d.comb += out_do_z.eq(self.out_do_z)
66
67 def elaborate(self, platform):
68 m = Module()
69
70 m.submodules.sc_in_a = self.in_a
71 m.submodules.sc_in_b = self.in_b
72 m.submodules.sc_out_z = self.out_z
73
74 s_nomatch = Signal()
75 m.d.comb += s_nomatch.eq(self.in_a.s != self.in_b.s)
76
77 m_match = Signal()
78 m.d.comb += m_match.eq(self.in_a.m == self.in_b.m)
79
80 # if a is NaN or b is NaN return NaN
81 with m.If(self.in_a.is_nan | self.in_b.is_nan):
82 m.d.comb += self.out_do_z.eq(1)
83 m.d.comb += self.out_z.nan(0)
84
85 # XXX WEIRDNESS for FP16 non-canonical NaN handling
86 # under review
87
88 ## if a is zero and b is NaN return -b
89 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
90 # m.d.comb += self.out_do_z.eq(1)
91 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
92
93 ## if b is zero and a is NaN return -a
94 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
95 # m.d.comb += self.out_do_z.eq(1)
96 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
97
98 ## if a is -zero and b is NaN return -b
99 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
100 # m.d.comb += self.out_do_z.eq(1)
101 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
102
103 ## if b is -zero and a is NaN return -a
104 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
105 # m.d.comb += self.out_do_z.eq(1)
106 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
107
108 # if a is inf return inf (or NaN)
109 with m.Elif(self.in_a.is_inf):
110 m.d.comb += self.out_do_z.eq(1)
111 m.d.comb += self.out_z.inf(self.in_a.s)
112 # if a is inf and signs don't match return NaN
113 with m.If(self.in_b.exp_128 & s_nomatch):
114 m.d.comb += self.out_z.nan(0)
115
116 # if b is inf return inf
117 with m.Elif(self.in_b.is_inf):
118 m.d.comb += self.out_do_z.eq(1)
119 m.d.comb += self.out_z.inf(self.in_b.s)
120
121 # if a is zero and b zero return signed-a/b
122 with m.Elif(self.in_a.is_zero & self.in_b.is_zero):
123 m.d.comb += self.out_do_z.eq(1)
124 m.d.comb += self.out_z.create(self.in_a.s & self.in_b.s,
125 self.in_b.e,
126 self.in_b.m[3:-1])
127
128 # if a is zero return b
129 with m.Elif(self.in_a.is_zero):
130 m.d.comb += self.out_do_z.eq(1)
131 m.d.comb += self.out_z.create(self.in_b.s, self.in_b.e,
132 self.in_b.m[3:-1])
133
134 # if b is zero return a
135 with m.Elif(self.in_b.is_zero):
136 m.d.comb += self.out_do_z.eq(1)
137 m.d.comb += self.out_z.create(self.in_a.s, self.in_a.e,
138 self.in_a.m[3:-1])
139
140 # if a equal to -b return zero (+ve zero)
141 with m.Elif(s_nomatch & m_match & (self.in_a.e == self.in_b.e)):
142 m.d.comb += self.out_do_z.eq(1)
143 m.d.comb += self.out_z.zero(0)
144
145 # Denormalised Number checks
146 with m.Else():
147 m.d.comb += self.out_do_z.eq(0)
148
149 return m
150
151
152 class FPAddSpecialCases(FPState):
153 """ special cases: NaNs, infs, zeros, denormalised
154 NOTE: some of these are unique to add. see "Special Operations"
155 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
156 """
157
158 def __init__(self, width):
159 FPState.__init__(self, "special_cases")
160 self.mod = FPAddSpecialCasesMod(width)
161 self.out_z = FPNumOut(width, False)
162 self.out_do_z = Signal(reset_less=True)
163
164 def action(self, m):
165 with m.If(self.out_do_z):
166 m.d.sync += self.z.v.eq(self.out_z.v) # only take the output
167 m.next = "put_z"
168 with m.Else():
169 m.next = "denormalise"
170
171
172 class FPAddDeNormMod(FPState):
173
174 def __init__(self, width):
175 self.in_a = FPNumBase(width)
176 self.in_b = FPNumBase(width)
177 self.out_a = FPNumBase(width)
178 self.out_b = FPNumBase(width)
179
180 def setup(self, m, in_a, in_b, out_a, out_b):
181 """ links module to inputs and outputs
182 """
183 m.d.comb += self.in_a.copy(in_a)
184 m.d.comb += self.in_b.copy(in_b)
185 m.d.comb += out_a.copy(self.out_a)
186 m.d.comb += out_b.copy(self.out_b)
187
188 def elaborate(self, platform):
189 m = Module()
190 m.submodules.denorm_in_a = self.in_a
191 m.submodules.denorm_in_b = self.in_b
192 m.submodules.denorm_out_a = self.out_a
193 m.submodules.denorm_out_b = self.out_b
194 # hmmm, don't like repeating identical code
195 m.d.comb += self.out_a.copy(self.in_a)
196 with m.If(self.in_a.exp_n127):
197 m.d.comb += self.out_a.e.eq(self.in_a.N126) # limit a exponent
198 with m.Else():
199 m.d.comb += self.out_a.m[-1].eq(1) # set top mantissa bit
200
201 m.d.comb += self.out_b.copy(self.in_b)
202 with m.If(self.in_b.exp_n127):
203 m.d.comb += self.out_b.e.eq(self.in_b.N126) # limit a exponent
204 with m.Else():
205 m.d.comb += self.out_b.m[-1].eq(1) # set top mantissa bit
206
207 return m
208
209
210 class FPAddDeNorm(FPState):
211
212 def __init__(self, width):
213 FPState.__init__(self, "denormalise")
214 self.mod = FPAddDeNormMod(width)
215 self.out_a = FPNumBase(width)
216 self.out_b = FPNumBase(width)
217
218 def action(self, m):
219 # Denormalised Number checks
220 m.next = "align"
221 m.d.sync += self.a.copy(self.out_a)
222 m.d.sync += self.b.copy(self.out_b)
223
224
225 class FPAddAlignMultiMod(FPState):
226
227 def __init__(self, width):
228 self.in_a = FPNumBase(width)
229 self.in_b = FPNumBase(width)
230 self.out_a = FPNumIn(None, width)
231 self.out_b = FPNumIn(None, width)
232 self.exp_eq = Signal(reset_less=True)
233
234 def setup(self, m, in_a, in_b, out_a, out_b, exp_eq):
235 """ links module to inputs and outputs
236 """
237 m.d.comb += self.in_a.copy(in_a)
238 m.d.comb += self.in_b.copy(in_b)
239 m.d.comb += out_a.copy(self.out_a)
240 m.d.comb += out_b.copy(self.out_b)
241 m.d.comb += exp_eq.eq(self.exp_eq)
242
243 def elaborate(self, platform):
244 # This one however (single-cycle) will do the shift
245 # in one go.
246
247 m = Module()
248
249 #m.submodules.align_in_a = self.in_a
250 #m.submodules.align_in_b = self.in_b
251 m.submodules.align_out_a = self.out_a
252 m.submodules.align_out_b = self.out_b
253
254 # NOTE: this does *not* do single-cycle multi-shifting,
255 # it *STAYS* in the align state until exponents match
256
257 # exponent of a greater than b: shift b down
258 m.d.comb += self.exp_eq.eq(0)
259 m.d.comb += self.out_a.copy(self.in_a)
260 m.d.comb += self.out_b.copy(self.in_b)
261 agtb = Signal(reset_less=True)
262 altb = Signal(reset_less=True)
263 m.d.comb += agtb.eq(self.in_a.e > self.in_b.e)
264 m.d.comb += altb.eq(self.in_a.e < self.in_b.e)
265 with m.If(agtb):
266 m.d.comb += self.out_b.shift_down(self.in_b)
267 # exponent of b greater than a: shift a down
268 with m.Elif(altb):
269 m.d.comb += self.out_a.shift_down(self.in_a)
270 # exponents equal: move to next stage.
271 with m.Else():
272 m.d.comb += self.exp_eq.eq(1)
273 return m
274
275
276 class FPAddAlignMulti(FPState):
277
278 def __init__(self, width):
279 FPState.__init__(self, "align")
280 self.mod = FPAddAlignMultiMod(width)
281 self.out_a = FPNumIn(None, width)
282 self.out_b = FPNumIn(None, width)
283 self.exp_eq = Signal(reset_less=True)
284
285 def action(self, m):
286 m.d.sync += self.a.copy(self.out_a)
287 m.d.sync += self.b.copy(self.out_b)
288 with m.If(self.exp_eq):
289 m.next = "add_0"
290
291
292 class FPAddAlignSingleMod:
293
294 def __init__(self, width):
295 self.in_a = FPNumBase(width)
296 self.in_b = FPNumBase(width)
297 self.out_a = FPNumIn(None, width)
298 self.out_b = FPNumIn(None, width)
299 #self.out_a = FPNumBase(width)
300 #self.out_b = FPNumBase(width)
301
302 def setup(self, m, in_a, in_b, out_a, out_b):
303 """ links module to inputs and outputs
304 """
305 m.d.comb += self.in_a.copy(in_a)
306 m.d.comb += self.in_b.copy(in_b)
307 m.d.comb += out_a.copy(self.out_a)
308 m.d.comb += out_b.copy(self.out_b)
309
310 def elaborate(self, platform):
311 # This one however (single-cycle) will do the shift
312 # in one go.
313
314 m = Module()
315
316 #m.submodules.align_in_a = self.in_a
317 #m.submodules.align_in_b = self.in_b
318 m.submodules.align_out_a = self.out_a
319 m.submodules.align_out_b = self.out_b
320
321 # XXX TODO: the shifter used here is quite expensive
322 # having only one would be better
323
324 ediff = Signal((len(self.in_a.e), True), reset_less=True)
325 ediffr = Signal((len(self.in_a.e), True), reset_less=True)
326 m.d.comb += ediff.eq(self.in_a.e - self.in_b.e)
327 m.d.comb += ediffr.eq(self.in_b.e - self.in_a.e)
328 m.d.comb += self.out_a.copy(self.in_a)
329 m.d.comb += self.out_b.copy(self.in_b)
330 with m.If(ediff > 0):
331 m.d.comb += self.out_b.shift_down_multi(ediff)
332 # exponent of b greater than a: shift a down
333 with m.Elif(ediff < 0):
334 m.d.comb += self.out_a.shift_down_multi(ediffr)
335 return m
336
337
338 class FPAddAlignSingle(FPState):
339
340 def __init__(self, width):
341 FPState.__init__(self, "align")
342 self.mod = FPAddAlignSingleMod(width)
343 self.out_a = FPNumIn(None, width)
344 self.out_b = FPNumIn(None, width)
345
346 def action(self, m):
347 m.d.sync += self.a.copy(self.out_a)
348 m.d.sync += self.b.copy(self.out_b)
349 m.next = "add_0"
350
351
352 class FPAddStage0Mod:
353
354 def __init__(self, width):
355 self.in_a = FPNumBase(width)
356 self.in_b = FPNumBase(width)
357 self.in_z = FPNumBase(width, False)
358 self.out_z = FPNumBase(width, False)
359 self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
360
361 def setup(self, m, in_a, in_b, in_z, out_z, out_tot):
362 """ links module to inputs and outputs
363 """
364 m.d.comb += self.in_a.copy(in_a)
365 m.d.comb += self.in_b.copy(in_b)
366 m.d.comb += self.in_z.copy(in_z)
367 m.d.comb += out_z.copy(self.out_z)
368 m.d.comb += out_tot.eq(self.out_tot)
369
370 def elaborate(self, platform):
371 m = Module()
372 #m.submodules.add0_in_a = self.in_a
373 #m.submodules.add0_in_b = self.in_b
374 #m.submodules.add0_in_z = self.in_z
375 #m.submodules.add0_out_z = self.out_z
376
377 m.d.comb += self.out_z.e.eq(self.in_a.e)
378 # same-sign (both negative or both positive) add mantissas
379 with m.If(self.in_a.s == self.in_b.s):
380 m.d.comb += [
381 self.out_tot.eq(Cat(self.in_a.m, 0) + Cat(self.in_b.m, 0)),
382 self.out_z.s.eq(self.in_a.s)
383 ]
384 # a mantissa greater than b, use a
385 with m.Elif(self.in_a.m >= self.in_b.m):
386 m.d.comb += [
387 self.out_tot.eq(Cat(self.in_a.m, 0) - Cat(self.in_b.m, 0)),
388 self.out_z.s.eq(self.in_a.s)
389 ]
390 # b mantissa greater than a, use b
391 with m.Else():
392 m.d.comb += [
393 self.out_tot.eq(Cat(self.in_b.m, 0) - Cat(self.in_a.m, 0)),
394 self.out_z.s.eq(self.in_b.s)
395 ]
396 return m
397
398
399 class FPAddStage0(FPState):
400 """ First stage of add. covers same-sign (add) and subtract
401 special-casing when mantissas are greater or equal, to
402 give greatest accuracy.
403 """
404
405 def __init__(self, width):
406 FPState.__init__(self, "add_0")
407 self.mod = FPAddStage0Mod(width)
408 self.out_z = FPNumBase(width, False)
409 self.out_tot = Signal(self.out_z.m_width + 4, reset_less=True)
410
411 def action(self, m):
412 m.next = "add_1"
413 m.d.sync += self.z.copy(self.out_z)
414
415
416 class FPAddStage1Mod(FPState):
417 """ Second stage of add: preparation for normalisation.
418 detects when tot sum is too big (tot[27] is kinda a carry bit)
419 """
420
421 def __init__(self, width):
422 self.out_norm = Signal(reset_less=True)
423 self.in_z = FPNumBase(width, False)
424 self.in_tot = Signal(self.in_z.m_width + 4, reset_less=True)
425 self.out_z = FPNumBase(width, False)
426 self.out_of = Overflow()
427
428 def setup(self, m, in_tot, in_z, out_z, out_of):
429 """ links module to inputs and outputs
430 """
431 m.d.comb += self.in_z.copy(in_z)
432 m.d.comb += self.in_tot.eq(in_tot)
433 m.d.comb += out_z.copy(self.out_z)
434 m.d.comb += out_of.copy(self.out_of)
435
436 def elaborate(self, platform):
437 m = Module()
438 #m.submodules.norm1_in_overflow = self.in_of
439 #m.submodules.norm1_out_overflow = self.out_of
440 #m.submodules.norm1_in_z = self.in_z
441 #m.submodules.norm1_out_z = self.out_z
442 m.d.comb += self.out_z.copy(self.in_z)
443 # tot[27] gets set when the sum overflows. shift result down
444 with m.If(self.in_tot[-1]):
445 m.d.comb += [
446 self.out_z.m.eq(self.in_tot[4:]),
447 self.out_of.m0.eq(self.in_tot[4]),
448 self.out_of.guard.eq(self.in_tot[3]),
449 self.out_of.round_bit.eq(self.in_tot[2]),
450 self.out_of.sticky.eq(self.in_tot[1] | self.in_tot[0]),
451 self.out_z.e.eq(self.in_z.e + 1)
452 ]
453 # tot[27] zero case
454 with m.Else():
455 m.d.comb += [
456 self.out_z.m.eq(self.in_tot[3:]),
457 self.out_of.m0.eq(self.in_tot[3]),
458 self.out_of.guard.eq(self.in_tot[2]),
459 self.out_of.round_bit.eq(self.in_tot[1]),
460 self.out_of.sticky.eq(self.in_tot[0])
461 ]
462 return m
463
464
465 class FPAddStage1(FPState):
466
467 def __init__(self, width):
468 FPState.__init__(self, "add_1")
469 self.mod = FPAddStage1Mod(width)
470 self.out_z = FPNumBase(width, False)
471 self.out_of = Overflow()
472
473 def action(self, m):
474 m.d.sync += self.of.copy(self.out_of)
475 m.d.sync += self.z.copy(self.out_z)
476 m.next = "normalise_1"
477
478
479 class FPNorm1Mod:
480
481 def __init__(self, width):
482 self.out_norm = Signal(reset_less=True)
483 self.in_z = FPNumBase(width, False)
484 self.out_z = FPNumBase(width, False)
485 self.in_of = Overflow()
486 self.out_of = Overflow()
487
488 def setup(self, m, in_z, out_z, in_of, out_of, out_norm):
489 """ links module to inputs and outputs
490 """
491 m.d.comb += self.in_z.copy(in_z)
492 m.d.comb += out_z.copy(self.out_z)
493 m.d.comb += self.in_of.copy(in_of)
494 m.d.comb += out_of.copy(self.out_of)
495 m.d.comb += out_norm.eq(self.out_norm)
496
497 def elaborate(self, platform):
498 m = Module()
499 m.submodules.norm1_in_overflow = self.in_of
500 m.submodules.norm1_out_overflow = self.out_of
501 m.submodules.norm1_in_z = self.in_z
502 m.submodules.norm1_out_z = self.out_z
503 m.d.comb += self.out_z.copy(self.in_z)
504 m.d.comb += self.out_of.copy(self.in_of)
505 m.d.comb += self.out_norm.eq((self.in_z.m_msbzero) & \
506 (self.in_z.exp_gt_n126))
507 with m.If(self.out_norm):
508 m.d.comb += [
509 self.out_z.e.eq(self.in_z.e - 1), # DECREASE exponent
510 self.out_z.m.eq(self.in_z.m << 1), # shift mantissa UP
511 self.out_z.m[0].eq(self.in_of.guard), # steal guard (was tot[2])
512 self.out_of.guard.eq(self.in_of.round_bit), # round (was tot[1])
513 self.out_of.round_bit.eq(0), # reset round bit
514 self.out_of.m0.eq(self.in_of.guard),
515 ]
516
517 return m
518
519
520 class FPNorm1(FPState):
521
522 def __init__(self, width):
523 FPState.__init__(self, "normalise_1")
524 self.mod = FPNorm1Mod(width)
525 self.out_norm = Signal(reset_less=True)
526 self.out_z = FPNumBase(width)
527 self.out_of = Overflow()
528
529 def action(self, m):
530 m.d.sync += self.of.copy(self.out_of)
531 m.d.sync += self.z.copy(self.out_z)
532 with m.If(~self.out_norm):
533 m.next = "normalise_2"
534
535
536 class FPNorm2Mod:
537
538 def __init__(self, width):
539 self.out_norm = Signal(reset_less=True)
540 self.in_z = FPNumBase(width, False)
541 self.out_z = FPNumBase(width, False)
542 self.in_of = Overflow()
543 self.out_of = Overflow()
544
545 def setup(self, m, in_z, out_z, in_of, out_of, out_norm):
546 """ links module to inputs and outputs
547 """
548 m.d.comb += self.in_z.copy(in_z)
549 m.d.comb += out_z.copy(self.out_z)
550 m.d.comb += self.in_of.copy(in_of)
551 m.d.comb += out_of.copy(self.out_of)
552 m.d.comb += out_norm.eq(self.out_norm)
553
554 def elaborate(self, platform):
555 m = Module()
556 m.submodules.norm2_in_overflow = self.in_of
557 m.submodules.norm2_out_overflow = self.out_of
558 m.submodules.norm2_in_z = self.in_z
559 m.submodules.norm2_out_z = self.out_z
560 m.d.comb += self.out_z.copy(self.in_z)
561 m.d.comb += self.out_of.copy(self.in_of)
562 m.d.comb += self.out_norm.eq(self.in_z.exp_lt_n126)
563 with m.If(self.out_norm):
564 m.d.comb += [
565 self.out_z.e.eq(self.in_z.e + 1), # INCREASE exponent
566 self.out_z.m.eq(self.in_z.m >> 1), # shift mantissa DOWN
567 self.out_of.guard.eq(self.in_z.m[0]),
568 self.out_of.m0.eq(self.in_z.m[1]),
569 self.out_of.round_bit.eq(self.in_of.guard),
570 self.out_of.sticky.eq(self.in_of.sticky | self.in_of.round_bit)
571 ]
572
573 return m
574
575
576 class FPNorm2(FPState):
577
578 def __init__(self, width):
579 FPState.__init__(self, "normalise_2")
580 self.mod = FPNorm2Mod(width)
581 self.out_norm = Signal(reset_less=True)
582 self.out_z = FPNumBase(width)
583 self.out_of = Overflow()
584
585 def action(self, m):
586 m.d.sync += self.of.copy(self.out_of)
587 m.d.sync += self.z.copy(self.out_z)
588 with m.If(~self.out_norm):
589 m.next = "round"
590
591
592 class FPRoundMod:
593
594 def __init__(self, width):
595 self.in_roundz = Signal(reset_less=True)
596 self.in_z = FPNumBase(width, False)
597 self.out_z = FPNumBase(width, False)
598
599 def setup(self, m, in_z, out_z, in_of):
600 """ links module to inputs and outputs
601 """
602 m.d.comb += self.in_z.copy(in_z)
603 m.d.comb += out_z.copy(self.out_z)
604 m.d.comb += self.in_roundz.eq(in_of.roundz)
605
606 def elaborate(self, platform):
607 m = Module()
608 m.d.comb += self.out_z.copy(self.in_z)
609 with m.If(self.in_roundz):
610 m.d.comb += self.out_z.m.eq(self.in_z.m + 1) # mantissa rounds up
611 with m.If(self.in_z.m == self.in_z.m1s): # all 1s
612 m.d.comb += self.out_z.e.eq(self.in_z.e + 1) # exponent up
613 return m
614
615
616 class FPRound(FPState):
617
618 def __init__(self, width):
619 FPState.__init__(self, "round")
620 self.mod = FPRoundMod(width)
621 self.out_z = FPNumBase(width)
622
623 def action(self, m):
624 m.d.sync += self.z.copy(self.out_z)
625 m.next = "corrections"
626
627
628 class FPCorrectionsMod:
629
630 def __init__(self, width):
631 self.in_z = FPNumOut(width, False)
632 self.out_z = FPNumOut(width, False)
633
634 def setup(self, m, in_z, out_z):
635 """ links module to inputs and outputs
636 """
637 m.d.comb += self.in_z.copy(in_z)
638 m.d.comb += out_z.copy(self.out_z)
639
640 def elaborate(self, platform):
641 m = Module()
642 m.submodules.corr_in_z = self.in_z
643 m.submodules.corr_out_z = self.out_z
644 m.d.comb += self.out_z.copy(self.in_z)
645 with m.If(self.in_z.is_denormalised):
646 m.d.comb += self.out_z.e.eq(self.in_z.N127)
647
648 # with m.If(self.in_z.is_overflowed):
649 # m.d.comb += self.out_z.inf(self.in_z.s)
650 # with m.Else():
651 # m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
652 return m
653
654
655 class FPCorrections(FPState):
656
657 def __init__(self, width):
658 FPState.__init__(self, "corrections")
659 self.mod = FPCorrectionsMod(width)
660 self.out_z = FPNumBase(width)
661
662 def action(self, m):
663 m.d.sync += self.z.copy(self.out_z)
664 m.next = "pack"
665
666
667 class FPPackMod:
668
669 def __init__(self, width):
670 self.in_z = FPNumOut(width, False)
671 self.out_z = FPNumOut(width, False)
672
673 def setup(self, m, in_z, out_z):
674 """ links module to inputs and outputs
675 """
676 m.d.comb += self.in_z.copy(in_z)
677 m.d.comb += out_z.v.eq(self.out_z.v)
678
679 def elaborate(self, platform):
680 m = Module()
681 m.submodules.pack_in_z = self.in_z
682 with m.If(self.in_z.is_overflowed):
683 m.d.comb += self.out_z.inf(self.in_z.s)
684 with m.Else():
685 m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
686 return m
687
688
689 class FPPack(FPState):
690
691 def __init__(self, width):
692 FPState.__init__(self, "pack")
693 self.mod = FPPackMod(width)
694 self.out_z = FPNumOut(width, False)
695
696 def action(self, m):
697 m.d.sync += self.z.v.eq(self.out_z.v)
698 m.next = "put_z"
699
700
701 class FPPutZ(FPState):
702
703 def action(self, m):
704 self.put_z(m, self.z, self.out_z, "get_a")
705
706
707 class FPADD:
708
709 def __init__(self, width, single_cycle=False):
710 self.width = width
711 self.single_cycle = single_cycle
712
713 self.in_a = FPOp(width)
714 self.in_b = FPOp(width)
715 self.out_z = FPOp(width)
716
717 self.states = []
718
719 def add_state(self, state):
720 self.states.append(state)
721 return state
722
723 def get_fragment(self, platform=None):
724 """ creates the HDL code-fragment for FPAdd
725 """
726 m = Module()
727
728 # Latches
729 #a = FPNumIn(self.in_a, self.width)
730 b = FPNumIn(self.in_b, self.width)
731 z = FPNumOut(self.width, False)
732
733 m.submodules.fpnum_b = b
734 m.submodules.fpnum_z = z
735
736 w = z.m_width + 4
737
738 of = Overflow()
739 m.submodules.overflow = of
740
741 geta = self.add_state(FPGetOpA(self.in_a, self.width))
742 #geta.set_inputs({"in_a": self.in_a})
743 #geta.set_outputs({"a": a})
744 a = geta.a
745 # XXX m.d.comb += a.v.eq(self.in_a.v) # links in_a to a
746 m.submodules.fpnum_a = a
747
748 getb = self.add_state(FPGetOpB("get_b"))
749 getb.set_inputs({"in_b": self.in_b})
750 getb.set_outputs({"b": b})
751 # XXX m.d.comb += b.v.eq(self.in_b.v) # links in_b to b
752
753 sc = self.add_state(FPAddSpecialCases(self.width))
754 sc.set_inputs({"a": a, "b": b})
755 sc.set_outputs({"z": z})
756 sc.mod.setup(m, a, b, sc.out_z, sc.out_do_z)
757 m.submodules.specialcases = sc.mod
758
759 dn = self.add_state(FPAddDeNorm(self.width))
760 dn.set_inputs({"a": a, "b": b})
761 dn.set_outputs({"a": a, "b": b}) # XXX outputs same as inputs
762 dn.mod.setup(m, a, b, dn.out_a, dn.out_b)
763 m.submodules.denormalise = dn.mod
764
765 if self.single_cycle:
766 alm = self.add_state(FPAddAlignSingle(self.width))
767 alm.set_inputs({"a": a, "b": b})
768 alm.set_outputs({"a": a, "b": b}) # XXX outputs same as inputs
769 alm.mod.setup(m, a, b, alm.out_a, alm.out_b)
770 else:
771 alm = self.add_state(FPAddAlignMulti(self.width))
772 alm.set_inputs({"a": a, "b": b})
773 alm.set_outputs({"a": a, "b": b}) # XXX outputs same as inputs
774 alm.mod.setup(m, a, b, alm.out_a, alm.out_b, alm.exp_eq)
775 m.submodules.align = alm.mod
776
777 add0 = self.add_state(FPAddStage0(self.width))
778 add0.set_inputs({"a": a, "b": b})
779 add0.set_outputs({"z": z})
780 add0.mod.setup(m, a, b, z, add0.out_z, add0.out_tot)
781 m.submodules.add0 = add0.mod
782
783 add1 = self.add_state(FPAddStage1(self.width))
784 add1.set_inputs({"tot": add0.out_tot, "z": add0.out_z})
785 add1.set_outputs({"z": z, "of": of}) # XXX Z as output
786 add1.mod.setup(m, add0.out_tot, z, add1.out_z, add1.out_of)
787 m.submodules.add1 = add1.mod
788
789 n1 = self.add_state(FPNorm1(self.width))
790 n1.set_inputs({"z": z, "of": of}) # XXX Z as output
791 n1.set_outputs({"z": z}) # XXX Z as output
792 n1.mod.setup(m, z, n1.out_z, of, n1.out_of, n1.out_norm)
793 m.submodules.normalise_1 = n1.mod
794
795 n2 = self.add_state(FPNorm2(self.width))
796 n2.set_inputs({"z": n1.out_z, "of": of})
797 n2.set_outputs({"z": z})
798 n2.mod.setup(m, n1.out_z, n2.out_z, of, n2.out_of, n2.out_norm)
799 m.submodules.normalise_2 = n2.mod
800
801 rn = self.add_state(FPRound(self.width))
802 rn.set_inputs({"z": n2.out_z, "of": of})
803 rn.set_outputs({"z": z})
804 rn.mod.setup(m, n2.out_z, rn.out_z, of)
805 m.submodules.roundz = rn.mod
806
807 cor = self.add_state(FPCorrections(self.width))
808 cor.set_inputs({"z": z}) # XXX Z as output
809 cor.set_outputs({"z": z}) # XXX Z as output
810 cor.mod.setup(m, z, cor.out_z)
811 m.submodules.corrections = cor.mod
812
813 pa = self.add_state(FPPack(self.width))
814 pa.set_inputs({"z": z}) # XXX Z as output
815 pa.set_outputs({"z": z}) # XXX Z as output
816 pa.mod.setup(m, z, pa.out_z)
817 m.submodules.pack = pa.mod
818
819 pz = self.add_state(FPPutZ("put_z"))
820 pz.set_inputs({"z": z})
821 pz.set_outputs({"out_z": self.out_z})
822
823 with m.FSM() as fsm:
824
825 for state in self.states:
826 with m.State(state.state_from):
827 state.action(m)
828
829 return m
830
831
832 if __name__ == "__main__":
833 alu = FPADD(width=32)
834 main(alu, ports=alu.in_a.ports() + alu.in_b.ports() + alu.out_z.ports())
835
836
837 # works... but don't use, just do "python fname.py convert -t v"
838 #print (verilog.convert(alu, ports=[
839 # ports=alu.in_a.ports() + \
840 # alu.in_b.ports() + \
841 # alu.out_z.ports())