switch to exact version of cython
[ieee754fpu.git] / src / ieee754 / fpadd / align.py
1 """IEEE754 Floating Point Library
2
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4
5 """
6
7 from nmigen import Module, Signal, Mux
8 from nmigen.cli import main, verilog
9
10 from nmutil.pipemodbase import PipeModBase
11 from ieee754.fpcommon.fpbase import FPNumBaseRecord
12 from ieee754.fpcommon.fpbase import MultiShiftRMerge
13 from ieee754.fpcommon.denorm import FPSCData
14 from ieee754.fpcommon.getop import FPPipeContext
15 from ieee754.fpcommon.pscdata import FPSCData
16
17
18 class FPAddAlignMultiMod:
19 """Module to do mantissa alignment shift in multiple cycles
20 """
21 def __init__(self, width):
22 self.in_a = FPNumBaseRecord(width)
23 self.in_b = FPNumBaseRecord(width)
24 self.out_a = FPNumBaseRecord(width)
25 self.out_b = FPNumBaseRecord(width)
26 self.exp_eq = Signal(reset_less=True)
27
28 def elaborate(self, platform):
29 m = Module()
30 comb = m.d.comb
31
32 # exponent of a greater than b: shift b down
33 comb += self.exp_eq.eq(0)
34 comb += self.out_a.eq(self.in_a)
35 comb += self.out_b.eq(self.in_b)
36 agtb = Signal(reset_less=True)
37 altb = Signal(reset_less=True)
38 comb += agtb.eq(self.in_a.e > self.in_b.e)
39 comb += altb.eq(self.in_a.e < self.in_b.e)
40 with m.If(agtb):
41 comb += self.out_b.shift_down(self.in_b)
42 # exponent of b greater than a: shift a down
43 with m.Elif(altb):
44 comb += self.out_a.shift_down(self.in_a)
45 # exponents equal: move to next stage.
46 with m.Else():
47 comb += self.exp_eq.eq(1)
48 return m
49
50
51 class FPAddAlignSingleMod(PipeModBase):
52
53 def __init__(self, pspec):
54 super().__init__(pspec, "align")
55
56 def ispec(self):
57 return FPSCData(self.pspec, True)
58
59 def ospec(self):
60 return FPSCData(self.pspec, True)
61
62 def elaborate(self, platform):
63 """ Aligns A against B or B against A, depending on which has the
64 greater exponent. This is done in a *single* cycle using
65 variable-width bit-shift
66
67 the shifter used here is quite expensive in terms of gates.
68 Mux A or B in (and out) into temporaries, as only one of them
69 needs to be aligned against the other.
70
71 code is therefore slightly complex because after testing which
72 exponent is greater, a and b get mux-routed into the multi-shifter
73 and so does the output.
74 """
75 m = Module()
76 comb = m.d.comb
77
78 ai = self.i.a
79 bi = self.i.b
80 width = self.pspec.width
81 espec = (len(ai.e), True)
82
83 # temporary (muxed) input and output to be shifted
84 t_inp = FPNumBaseRecord(width)
85 t_out = FPNumBaseRecord(width)
86 msr = MultiShiftRMerge(ai.m_width, espec)
87 m.submodules.multishift_r = msr
88
89 # temporaries
90 ediff = Signal(espec, reset_less=True)
91 ediffr = Signal(espec, reset_less=True)
92 tdiff = Signal(espec, reset_less=True)
93 elz = Signal(reset_less=True)
94 egz = Signal(reset_less=True)
95
96 # connect multi-shifter to t_inp/out mantissa (and tdiff)
97 # (only one: input/output is muxed)
98 comb += msr.inp.eq(t_inp.m)
99 comb += msr.diff.eq(tdiff)
100 comb += t_out.m.eq(msr.m)
101 comb += t_out.e.eq(Mux(egz, ai.e, bi.e))
102 comb += t_out.s.eq(t_inp.s)
103
104 # work out exponent difference, set up mux-tests if a > b or b > a
105 comb += ediff.eq(ai.e - bi.e) # a - b
106 comb += ediffr.eq(-ediff) # b - a
107 comb += elz.eq(ediffr > 0) # ae < be
108 comb += egz.eq(ediff > 0) # ae > be
109
110 # decide what to input into the multi-shifter
111 comb += [t_inp.s.eq(Mux(egz, bi.s, ai.s)), # a/b sign
112 t_inp.m.eq(Mux(egz, bi.m, ai.m)), # a/b mantissa
113 t_inp.e.eq(Mux(egz, bi.e, ai.e)), # a/b exponent
114 tdiff.eq(Mux(egz, ediff, ediffr)),
115 ]
116
117 # now decide where (if) to route the *output* of the multi-shifter
118
119 # if a exponent greater, route mshifted-out to b? otherwise just b
120 comb += [self.o.b.e.eq(Mux(egz, t_out.e, bi.e)), # exponent
121 self.o.b.m.eq(Mux(egz, t_out.m, bi.m)), # mantissa
122 self.o.b.s.eq(bi.s), # sign as-is
123 ]
124 # if b exponent greater, route mshifted-out to a? otherwise just a
125 comb += [self.o.a.e.eq(Mux(elz, t_out.e, ai.e)), # exponent
126 self.o.a.m.eq(Mux(elz, t_out.m, ai.m)), # mantissa
127 self.o.a.s.eq(ai.s), # sign as-is
128 ]
129
130 # pass context through
131 comb += self.o.ctx.eq(self.i.ctx)
132 comb += self.o.z.eq(self.i.z)
133 comb += self.o.out_do_z.eq(self.i.out_do_z)
134 comb += self.o.oz.eq(self.i.oz)
135 comb += self.o.rm.eq(self.i.rm)
136
137 return m
138