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