big convert g/s/r mid --> muxid
[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, Elaboratable
6 from nmigen.cli import main, verilog
7
8 from ieee754.fpcommon.fpbase import FPNumOut, FPNumIn, FPNumBase
9 from ieee754.fpcommon.fpbase import FPNumBaseRecord
10 from ieee754.fpcommon.fpbase import MultiShiftRMerge
11 from ieee754.fpcommon.fpbase import FPState
12 from ieee754.fpcommon.denorm import FPSCData
13 from ieee754.fpcommon.getop import FPBaseData
14
15
16 class FPNumIn2Ops:
17
18 def __init__(self, width, pspec):
19 self.a = FPNumBaseRecord(width)
20 self.b = FPNumBaseRecord(width)
21 self.z = FPNumBaseRecord(width, False)
22 self.out_do_z = Signal(reset_less=True)
23 self.oz = Signal(width, reset_less=True)
24 self.ctx = FPBaseData(width, pspec)
25 self.muxid = self.ctx.muxid
26
27 def eq(self, i):
28 return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz),
29 self.a.eq(i.a), self.b.eq(i.b), self.ctx.eq(i.ctx)]
30
31
32
33 class FPAddAlignMultiMod(FPState):
34
35 def __init__(self, width):
36 self.in_a = FPNumBaseRecord(width)
37 self.in_b = FPNumBaseRecord(width)
38 self.out_a = FPNumBaseRecord(width)
39 self.out_b = FPNumBaseRecord(width)
40 self.exp_eq = Signal(reset_less=True)
41
42 def elaborate(self, platform):
43 # This one however (single-cycle) will do the shift
44 # in one go.
45
46 m = Module()
47
48 #m.submodules.align_in_a = self.in_a
49 #m.submodules.align_in_b = self.in_b
50 #m.submodules.align_out_a = self.out_a
51 #m.submodules.align_out_b = self.out_b
52
53 # NOTE: this does *not* do single-cycle multi-shifting,
54 # it *STAYS* in the align state until exponents match
55
56 # exponent of a greater than b: shift b down
57 m.d.comb += self.exp_eq.eq(0)
58 m.d.comb += self.out_a.eq(self.in_a)
59 m.d.comb += self.out_b.eq(self.in_b)
60 agtb = Signal(reset_less=True)
61 altb = Signal(reset_less=True)
62 m.d.comb += agtb.eq(self.in_a.e > self.in_b.e)
63 m.d.comb += altb.eq(self.in_a.e < self.in_b.e)
64 with m.If(agtb):
65 m.d.comb += self.out_b.shift_down(self.in_b)
66 # exponent of b greater than a: shift a down
67 with m.Elif(altb):
68 m.d.comb += self.out_a.shift_down(self.in_a)
69 # exponents equal: move to next stage.
70 with m.Else():
71 m.d.comb += self.exp_eq.eq(1)
72 return m
73
74
75 class FPAddAlignMulti(FPState):
76
77 def __init__(self, width, pspec):
78 FPState.__init__(self, "align")
79 self.mod = FPAddAlignMultiMod(width, pspec)
80 self.out_a = FPNumBaseRecord(width)
81 self.out_b = FPNumBaseRecord(width)
82 self.exp_eq = Signal(reset_less=True)
83
84 def setup(self, m, in_a, in_b):
85 """ links module to inputs and outputs
86 """
87 m.submodules.align = self.mod
88 m.d.comb += self.mod.in_a.eq(in_a)
89 m.d.comb += self.mod.in_b.eq(in_b)
90 m.d.comb += self.exp_eq.eq(self.mod.exp_eq)
91 m.d.sync += self.out_a.eq(self.mod.out_a)
92 m.d.sync += self.out_b.eq(self.mod.out_b)
93
94 def action(self, m):
95 with m.If(self.exp_eq):
96 m.next = "add_0"
97
98
99 class FPAddAlignSingleMod(Elaboratable):
100
101 def __init__(self, width, pspec):
102 self.width = width
103 self.pspec = pspec
104 self.i = self.ispec()
105 self.o = self.ospec()
106
107 def ispec(self):
108 return FPSCData(self.width, self.pspec, True)
109
110 def ospec(self):
111 return FPNumIn2Ops(self.width, self.pspec)
112
113 def process(self, i):
114 return self.o
115
116 def setup(self, m, i):
117 """ links module to inputs and outputs
118 """
119 m.submodules.align = self
120 m.d.comb += self.i.eq(i)
121
122 def elaborate(self, platform):
123 """ Aligns A against B or B against A, depending on which has the
124 greater exponent. This is done in a *single* cycle using
125 variable-width bit-shift
126
127 the shifter used here is quite expensive in terms of gates.
128 Mux A or B in (and out) into temporaries, as only one of them
129 needs to be aligned against the other
130 """
131 m = Module()
132
133 #m.submodules.align_in_a = self.i.a
134 #m.submodules.align_in_b = self.i.b
135 #m.submodules.align_out_a = self.o.a
136 #m.submodules.align_out_b = self.o.b
137
138 # temporary (muxed) input and output to be shifted
139 t_inp = FPNumBaseRecord(self.width)
140 t_out = FPNumBaseRecord(self.width)
141 espec = (len(self.i.a.e), True)
142 msr = MultiShiftRMerge(self.i.a.m_width, espec)
143 #m.submodules.align_t_in = t_inp
144 #m.submodules.align_t_out = t_out
145 m.submodules.multishift_r = msr
146
147 ediff = Signal(espec, reset_less=True)
148 ediffr = Signal(espec, reset_less=True)
149 tdiff = Signal(espec, reset_less=True)
150 elz = Signal(reset_less=True)
151 egz = Signal(reset_less=True)
152
153 # connect multi-shifter to t_inp/out mantissa (and tdiff)
154 m.d.comb += msr.inp.eq(t_inp.m)
155 m.d.comb += msr.diff.eq(tdiff)
156 m.d.comb += t_out.m.eq(msr.m)
157 m.d.comb += t_out.e.eq(t_inp.e + tdiff)
158 m.d.comb += t_out.s.eq(t_inp.s)
159
160 m.d.comb += ediff.eq(self.i.a.e - self.i.b.e)
161 m.d.comb += ediffr.eq(self.i.b.e - self.i.a.e)
162 m.d.comb += elz.eq(self.i.a.e < self.i.b.e)
163 m.d.comb += egz.eq(self.i.a.e > self.i.b.e)
164
165 # default: A-exp == B-exp, A and B untouched (fall through)
166 m.d.comb += self.o.a.eq(self.i.a)
167 m.d.comb += self.o.b.eq(self.i.b)
168 # only one shifter (muxed)
169 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
170 # exponent of a greater than b: shift b down
171 with m.If(~self.i.out_do_z):
172 with m.If(egz):
173 m.d.comb += [t_inp.eq(self.i.b),
174 tdiff.eq(ediff),
175 self.o.b.eq(t_out),
176 self.o.b.s.eq(self.i.b.s), # whoops forgot sign
177 ]
178 # exponent of b greater than a: shift a down
179 with m.Elif(elz):
180 m.d.comb += [t_inp.eq(self.i.a),
181 tdiff.eq(ediffr),
182 self.o.a.eq(t_out),
183 self.o.a.s.eq(self.i.a.s), # whoops forgot sign
184 ]
185
186 m.d.comb += self.o.ctx.eq(self.i.ctx)
187 m.d.comb += self.o.z.eq(self.i.z)
188 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
189 m.d.comb += self.o.oz.eq(self.i.oz)
190
191 return m
192
193
194 class FPAddAlignSingle(FPState):
195
196 def __init__(self, width, pspec):
197 FPState.__init__(self, "align")
198 self.mod = FPAddAlignSingleMod(width, pspec)
199 self.out_a = FPNumIn(None, width)
200 self.out_b = FPNumIn(None, width)
201
202 def setup(self, m, i):
203 """ links module to inputs and outputs
204 """
205 self.mod.setup(m, i)
206
207 # NOTE: could be done as comb
208 m.d.sync += self.out_a.eq(self.mod.out_a)
209 m.d.sync += self.out_b.eq(self.mod.out_b)
210
211 def action(self, m):
212 m.next = "add_0"
213
214