remove use of out_do_z in add align
[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 # connect multi-shifter to t_inp/out mantissa (and tdiff)
89 # (only one: input/output is muxed)
90 comb += msr.inp.eq(t_inp.m)
91 comb += msr.diff.eq(tdiff)
92 comb += t_out.m.eq(msr.m)
93 comb += t_out.e.eq(t_inp.e + tdiff)
94 comb += t_out.s.eq(t_inp.s)
95
96 comb += ediff.eq(self.i.a.e - self.i.b.e) # a - b
97 comb += ediffr.eq(-ediff) # b - a
98 comb += elz.eq(self.i.a.e < self.i.b.e) # ae < be
99 comb += egz.eq(self.i.a.e > self.i.b.e) # ae > be
100
101 # default: A-exp == B-exp, A and B untouched (fall through)
102 comb += self.o.a.eq(self.i.a)
103 comb += self.o.b.eq(self.i.b)
104
105 # exponent of a greater than b: shift b down
106 with m.If(egz):
107 comb += [t_inp.eq(self.i.b),
108 tdiff.eq(ediff),
109 self.o.b.eq(t_out),
110 self.o.b.s.eq(self.i.b.s), # whoops forgot sign
111 ]
112 # exponent of b greater than a: shift a down
113 with m.Elif(elz):
114 comb += [t_inp.eq(self.i.a),
115 tdiff.eq(ediffr),
116 self.o.a.eq(t_out),
117 self.o.a.s.eq(self.i.a.s), # whoops forgot sign
118 ]
119
120 comb += self.o.ctx.eq(self.i.ctx)
121 comb += self.o.z.eq(self.i.z)
122 comb += self.o.out_do_z.eq(self.i.out_do_z)
123 comb += self.o.oz.eq(self.i.oz)
124
125 return m
126