move and reorg create_next_terms in AddReduceSingle, call in elaborate
[ieee754fpu.git] / src / ieee754 / fpadd / align.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
6 from nmigen.cli import main, verilog
7
8 from nmutil.pipemodbase import PipeModBase
9 from ieee754.fpcommon.fpbase import FPNumBaseRecord
10 from ieee754.fpcommon.fpbase import MultiShiftRMerge
11 from ieee754.fpcommon.denorm import FPSCData
12 from ieee754.fpcommon.getop import FPPipeContext
13 from ieee754.fpcommon.pscdata import FPSCData
14
15
16 class FPAddAlignMultiMod:
17 """Module to do mantissa alignment shift in multiple cycles
18 """
19 def __init__(self, width):
20 self.in_a = FPNumBaseRecord(width)
21 self.in_b = FPNumBaseRecord(width)
22 self.out_a = FPNumBaseRecord(width)
23 self.out_b = FPNumBaseRecord(width)
24 self.exp_eq = Signal(reset_less=True)
25
26 def elaborate(self, platform):
27 m = Module()
28 comb = m.d.comb
29
30 # exponent of a greater than b: shift b down
31 comb += self.exp_eq.eq(0)
32 comb += self.out_a.eq(self.in_a)
33 comb += self.out_b.eq(self.in_b)
34 agtb = Signal(reset_less=True)
35 altb = Signal(reset_less=True)
36 comb += agtb.eq(self.in_a.e > self.in_b.e)
37 comb += altb.eq(self.in_a.e < self.in_b.e)
38 with m.If(agtb):
39 comb += self.out_b.shift_down(self.in_b)
40 # exponent of b greater than a: shift a down
41 with m.Elif(altb):
42 comb += self.out_a.shift_down(self.in_a)
43 # exponents equal: move to next stage.
44 with m.Else():
45 comb += self.exp_eq.eq(1)
46 return m
47
48
49 class FPAddAlignSingleMod(PipeModBase):
50
51 def __init__(self, pspec):
52 super().__init__(pspec, "align")
53
54 def ispec(self):
55 return FPSCData(self.pspec, True)
56
57 def ospec(self):
58 return FPSCData(self.pspec, True)
59
60 def elaborate(self, platform):
61 """ Aligns A against B or B against A, depending on which has the
62 greater exponent. This is done in a *single* cycle using
63 variable-width bit-shift
64
65 the shifter used here is quite expensive in terms of gates.
66 Mux A or B in (and out) into temporaries, as only one of them
67 needs to be aligned against the other
68 """
69 m = Module()
70 comb = m.d.comb
71
72 # temporary (muxed) input and output to be shifted
73 width = self.pspec.width
74 espec = (len(self.i.a.e), True)
75
76 t_inp = FPNumBaseRecord(width)
77 t_out = FPNumBaseRecord(width)
78 msr = MultiShiftRMerge(self.i.a.m_width, espec)
79 m.submodules.multishift_r = msr
80
81 # temporaries
82 ediff = Signal(espec, reset_less=True)
83 ediffr = Signal(espec, reset_less=True)
84 tdiff = Signal(espec, reset_less=True)
85 elz = Signal(reset_less=True)
86 egz = Signal(reset_less=True)
87
88 with m.If(~self.i.out_do_z):
89 # connect multi-shifter to t_inp/out mantissa (and tdiff)
90 # (only one: input/output is muxed)
91 comb += msr.inp.eq(t_inp.m)
92 comb += msr.diff.eq(tdiff)
93 comb += t_out.m.eq(msr.m)
94 comb += t_out.e.eq(t_inp.e + tdiff)
95 comb += t_out.s.eq(t_inp.s)
96
97 comb += ediff.eq(self.i.a.e - self.i.b.e) # a - b
98 comb += ediffr.eq(-ediff) # b - a
99 comb += elz.eq(self.i.a.e < self.i.b.e) # ae < be
100 comb += egz.eq(self.i.a.e > self.i.b.e) # ae > be
101
102 # default: A-exp == B-exp, A and B untouched (fall through)
103 comb += self.o.a.eq(self.i.a)
104 comb += self.o.b.eq(self.i.b)
105
106 # exponent of a greater than b: shift b down
107 with m.If(egz):
108 comb += [t_inp.eq(self.i.b),
109 tdiff.eq(ediff),
110 self.o.b.eq(t_out),
111 self.o.b.s.eq(self.i.b.s), # whoops forgot sign
112 ]
113 # exponent of b greater than a: shift a down
114 with m.Elif(elz):
115 comb += [t_inp.eq(self.i.a),
116 tdiff.eq(ediffr),
117 self.o.a.eq(t_out),
118 self.o.a.s.eq(self.i.a.s), # whoops forgot sign
119 ]
120
121 comb += self.o.ctx.eq(self.i.ctx)
122 comb += self.o.z.eq(self.i.z)
123 comb += self.o.out_do_z.eq(self.i.out_do_z)
124 comb += self.o.oz.eq(self.i.oz)
125
126 return m
127