add bug cross-reference to #113 for FCVT unit tests
[ieee754fpu.git] / src / ieee754 / fcvt / pipeline.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, Cat, Const, Elaboratable
6 from nmigen.cli import main, verilog
7
8 from nmutil.singlepipe import ControlBase
9 from nmutil.concurrentunit import ReservationStations, num_bits
10
11 from ieee754.fpcommon.getop import FPADDBaseData
12 from ieee754.fpcommon.pack import FPPackData
13 from ieee754.fpcommon.normtopack import FPNormToPack
14 from ieee754.fpcommon.postcalc import FPAddStage1Data
15 from ieee754.fpcommon.msbhigh import FPMSBHigh
16 from ieee754.fpcommon.fpbase import MultiShiftRMerge
17
18
19 from nmigen import Module, Signal, Elaboratable
20 from math import log
21
22 from ieee754.fpcommon.fpbase import FPNumIn, FPNumOut, FPNumBaseRecord
23 from ieee754.fpcommon.fpbase import FPState, FPNumBase
24 from ieee754.fpcommon.getop import FPPipeContext
25
26 from ieee754.fpcommon.fpbase import FPNumDecode, FPNumBaseRecord
27 from nmutil.singlepipe import SimpleHandshake, StageChain
28
29 from ieee754.fpcommon.fpbase import FPState
30 from ieee754.pipeline import PipelineSpec
31
32
33 class SignedOp:
34 def __init__(self):
35 self.signed = Signal(reset_less=True)
36
37 def eq(self, i):
38 return [self.signed.eq(i)]
39
40
41 class FPCVTFloatToIntMod(Elaboratable):
42 """ integer to FP conversion: copes with 16/32/64 fp to 16/32/64 int/uint
43
44 self.ctx.i.op & 0x1 == 0x1 : SIGNED int
45 self.ctx.i.op & 0x1 == 0x0 : UNSIGNED int
46
47 Note: this is a single-stage conversion that goes direct to FPPackData
48 """
49 def __init__(self, in_pspec, out_pspec):
50 self.in_pspec = in_pspec
51 self.out_pspec = out_pspec
52 self.i = self.ispec()
53 self.o = self.ospec()
54
55 def ispec(self):
56 return FPADDBaseData(self.in_pspec)
57
58 def ospec(self):
59 return FPPackData(self.out_pspec)
60
61 def setup(self, m, i):
62 """ links module to inputs and outputs
63 """
64 m.submodules.upconvert = self
65 m.d.comb += self.i.eq(i)
66
67 def process(self, i):
68 return self.o
69
70 def elaborate(self, platform):
71 m = Module()
72
73 #m.submodules.sc_out_z = self.o.z
74
75 # decode: XXX really should move to separate stage
76 print("in_width out", self.in_pspec.width,
77 self.out_pspec.width)
78 a1 = FPNumBaseRecord(self.in_pspec.width, False)
79 print("a1", a1.width, a1.rmw, a1.e_width, a1.e_start, a1.e_end)
80 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
81 m.d.comb += a1.v.eq(self.i.a)
82 z1 = self.o.z
83 mz = len(self.o.z)
84 print("z1", mz)
85
86 me = a1.rmw
87 ms = mz - me
88 print("ms-me", ms, me)
89
90 espec = (len(a1.e_width), True)
91 ediff_intwid = Signal(espec, reset_less=True)
92
93 # conversion can mostly be done manually...
94 m.d.comb += self.o.z.s.eq(a1.s)
95 m.d.comb += self.o.z.e.eq(a1.e)
96 m.d.comb += self.o.z.m[ms:].eq(a1.m)
97 m.d.comb += self.o.z.create(a1.s, a1.e, self.o.z.m) # ... here
98
99 signed = Signal(reset_less=True)
100 m.d.comb += signed.eq(self.i.ctx.op[0])
101
102 # special cases
103 with m.If(a1.exp_n127):
104 m.d.comb += self.o.z.eq(0)
105
106 # signed, exp too big
107 with m.Elif(signed & (a1.e > Const(mz-1, espec))):
108 with m.If(a1.s): # negative FP, so negative overrun
109 m.d.comb += self.o.z.eq(-(1<<(mz-1)))
110 with m.Else(): # positive FP, so positive overrun
111 m.d.comb += self.o.z.eq((1<<(mz-1)-1))
112
113 # unsigned, exp too big
114 with m.Elif((~signed) & (a1.e > Const(mz, espec))):
115 with m.If(a1.s): # negative FP, so negative overrun (zero)
116 m.d.comb += self.o.z.eq(0)
117 with m.Else(): # positive FP, so positive overrun (max INT)
118 m.d.comb += self.o.z.eq((1<<(mz)-1))
119
120 # ok exp should be in range: shift it...
121 with m.Else():
122 mantissa = Signal(z1, reset_less=True)
123 l = [0] * ms + [1] + a1.m
124 m.d.comb += mantissa.eq(Cat(*l) >> a1.e)
125 m.d.comb += self.o.z.eq(mantissa)
126
127 # copy the context (muxid, operator)
128 m.d.comb += self.o.oz.eq(self.o.z.v)
129 m.d.comb += self.o.ctx.eq(self.i.ctx)
130
131 return m
132
133
134 class FPCVTIntToFloatMod(Elaboratable):
135 """ FP integer conversion: copes with 16/32/64 int to 16/32/64 fp.
136
137 self.ctx.i.op & 0x1 == 0x1 : SIGNED int
138 self.ctx.i.op & 0x1 == 0x0 : UNSIGNED int
139 """
140 def __init__(self, in_pspec, out_pspec):
141 self.in_pspec = in_pspec
142 self.out_pspec = out_pspec
143 self.i = self.ispec()
144 self.o = self.ospec()
145
146 def ispec(self):
147 return FPADDBaseData(self.in_pspec)
148
149 def ospec(self):
150 return FPAddStage1Data(self.out_pspec, e_extra=True)
151
152 def setup(self, m, i):
153 """ links module to inputs and outputs
154 """
155 m.submodules.intconvert = self
156 m.d.comb += self.i.eq(i)
157
158 def process(self, i):
159 return self.o
160
161 def elaborate(self, platform):
162 m = Module()
163
164 #m.submodules.sc_out_z = self.o.z
165
166 # decode: XXX really should move to separate stage
167 print("in_width out", self.in_pspec.width,
168 self.out_pspec.width)
169 print("a1", self.in_pspec.width)
170 z1 = self.o.z
171 print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end)
172
173 me = self.in_pspec.width
174 mz = self.o.z.rmw
175 ms = mz - me
176 print("ms-me", ms, me, mz)
177
178 # 3 extra bits for guard/round/sticky
179 msb = FPMSBHigh(me+3, z1.e_width)
180 m.submodules.norm_msb = msb
181
182 # signed or unsigned, use operator context
183 signed = Signal(reset_less=True)
184 m.d.comb += signed.eq(self.i.ctx.op[0])
185
186 # copy of mantissa (one less bit if signed)
187 mantissa = Signal(me, reset_less=True)
188
189 # detect signed/unsigned. key case: -ve numbers need inversion
190 # to +ve because the FP sign says if it's -ve or not.
191 with m.If(signed):
192 m.d.comb += z1.s.eq(self.i.a[-1]) # sign in top bit of a
193 with m.If(z1.s):
194 m.d.comb += mantissa.eq(-self.i.a) # invert input if sign -ve
195 with m.Else():
196 m.d.comb += mantissa.eq(self.i.a) # leave as-is
197 with m.Else():
198 m.d.comb += mantissa.eq(self.i.a) # unsigned, use full a
199 m.d.comb += z1.s.eq(0)
200
201 # set input from full INT
202 m.d.comb += msb.m_in.eq(Cat(0, 0, 0, mantissa)) # g/r/s + input
203 m.d.comb += msb.e_in.eq(me) # exp = int width
204
205 # to do with FP16... not yet resolved why
206 alternative = ms < 0
207
208 if alternative:
209 m.d.comb += z1.e.eq(msb.e_out-1)
210 mmsb = msb.m_out[-mz-1:]
211 if mz == 16:
212 # larger int to smaller FP (uint32/64 -> fp16 most likely)
213 m.d.comb += z1.m[ms-1:].eq(mmsb)
214 else: # 32? XXX weirdness...
215 m.d.comb += z1.m.eq(mmsb)
216 else:
217 # smaller int to larger FP
218 m.d.comb += z1.e.eq(msb.e_out)
219 m.d.comb += z1.m[ms:].eq(msb.m_out[3:])
220 m.d.comb += z1.create(z1.s, z1.e, z1.m) # ... here
221
222 # note: post-normalisation actually appears to be capable of
223 # detecting overflow to infinity (FPPackMod). so it's ok to
224 # drop the bits into the mantissa (with a fixed exponent),
225 # do some rounding (which might result in exceeding the
226 # range of the target FP by re-increasing the exponent),
227 # and basically *not* have to do any kind of range-checking
228 # here: just set up guard/round/sticky, drop the INT into the
229 # mantissa, and away we go. XXX TODO: see if FPNormaliseMod
230 # is even necessary. it probably isn't
231
232 # initialise rounding (but only activate if needed)
233 if alternative:
234 # larger int to smaller FP (uint32/64 -> fp16 most likely)
235 m.d.comb += self.o.of.guard.eq(msb.m_out[-mz-2])
236 m.d.comb += self.o.of.round_bit.eq(msb.m_out[-mz-3])
237 m.d.comb += self.o.of.sticky.eq(msb.m_out[:-mz-3].bool())
238 m.d.comb += self.o.of.m0.eq(msb.m_out[-mz-1])
239 else:
240 # smaller int to larger FP
241 m.d.comb += self.o.of.guard.eq(msb.m_out[2])
242 m.d.comb += self.o.of.round_bit.eq(msb.m_out[1])
243 m.d.comb += self.o.of.sticky.eq(msb.m_out[:1].bool())
244 m.d.comb += self.o.of.m0.eq(msb.m_out[3])
245
246 # special cases active by default
247 m.d.comb += self.o.out_do_z.eq(1)
248
249 # detect zero
250 with m.If(~self.i.a.bool()):
251 m.d.comb += self.o.z.zero(0)
252 with m.Else():
253 m.d.comb += self.o.out_do_z.eq(0) # activate normalisation
254
255 # copy the context (muxid, operator)
256 m.d.comb += self.o.oz.eq(self.o.z.v)
257 m.d.comb += self.o.ctx.eq(self.i.ctx)
258
259 return m
260
261
262 class FPCVTUpConvertMod(Elaboratable):
263 """ FP up-conversion (lower to higher bitwidth)
264 """
265 def __init__(self, in_pspec, out_pspec):
266 self.in_pspec = in_pspec
267 self.out_pspec = out_pspec
268 self.i = self.ispec()
269 self.o = self.ospec()
270
271 def ispec(self):
272 return FPADDBaseData(self.in_pspec)
273
274 def ospec(self):
275 return FPAddStage1Data(self.out_pspec, e_extra=False)
276
277 def setup(self, m, i):
278 """ links module to inputs and outputs
279 """
280 m.submodules.upconvert = self
281 m.d.comb += self.i.eq(i)
282
283 def process(self, i):
284 return self.o
285
286 def elaborate(self, platform):
287 m = Module()
288
289 #m.submodules.sc_out_z = self.o.z
290
291 # decode: XXX really should move to separate stage
292 print("in_width out", self.in_pspec.width,
293 self.out_pspec.width)
294 a1 = FPNumBaseRecord(self.in_pspec.width, False)
295 print("a1", a1.width, a1.rmw, a1.e_width, a1.e_start, a1.e_end)
296 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
297 m.d.comb += a1.v.eq(self.i.a)
298 z1 = self.o.z
299 print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end)
300
301 me = a1.rmw
302 ms = self.o.z.rmw - a1.rmw
303 print("ms-me", ms, me, self.o.z.rmw, a1.rmw)
304
305 # conversion can mostly be done manually...
306 m.d.comb += self.o.z.s.eq(a1.s)
307 m.d.comb += self.o.z.e.eq(a1.e)
308 m.d.comb += self.o.z.m[ms:].eq(a1.m)
309 m.d.comb += self.o.z.create(a1.s, a1.e, self.o.z.m) # ... here
310
311 # initialise rounding to all zeros (deactivate)
312 m.d.comb += self.o.of.guard.eq(0)
313 m.d.comb += self.o.of.round_bit.eq(0)
314 m.d.comb += self.o.of.sticky.eq(0)
315 m.d.comb += self.o.of.m0.eq(a1.m[0])
316
317 # most special cases active (except tiny-number normalisation, below)
318 m.d.comb += self.o.out_do_z.eq(1)
319
320 # detect NaN/Inf first
321 with m.If(a1.exp_128):
322 with m.If(~a1.m_zero):
323 m.d.comb += self.o.z.nan(0) # RISC-V wants normalised NaN
324 with m.Else():
325 m.d.comb += self.o.z.inf(a1.s) # RISC-V wants signed INF
326 with m.Else():
327 with m.If(a1.exp_n127):
328 with m.If(~a1.m_zero):
329 m.d.comb += self.o.z.m[ms:].eq(Cat(0, a1.m))
330 m.d.comb += self.o.out_do_z.eq(0) # activate normalisation
331 with m.Else():
332 # RISC-V zero needs actual zero
333 m.d.comb += self.o.z.zero(a1.s)
334
335 # copy the context (muxid, operator)
336 m.d.comb += self.o.oz.eq(self.o.z.v)
337 m.d.comb += self.o.ctx.eq(self.i.ctx)
338
339 return m
340
341
342 class FPCVTDownConvertMod(Elaboratable):
343 """ FP down-conversion (higher to lower bitwidth)
344 """
345 def __init__(self, in_pspec, out_pspec):
346 self.in_pspec = in_pspec
347 self.out_pspec = out_pspec
348 self.i = self.ispec()
349 self.o = self.ospec()
350
351 def ispec(self):
352 return FPADDBaseData(self.in_pspec)
353
354 def ospec(self):
355 return FPAddStage1Data(self.out_pspec, e_extra=True)
356
357 def setup(self, m, i):
358 """ links module to inputs and outputs
359 """
360 m.submodules.downconvert = self
361 m.d.comb += self.i.eq(i)
362
363 def process(self, i):
364 return self.o
365
366 def elaborate(self, platform):
367 m = Module()
368
369 #m.submodules.sc_out_z = self.o.z
370
371 # decode: XXX really should move to separate stage
372 print("in_width out", self.in_pspec.width,
373 self.out_pspec.width)
374 a1 = FPNumBaseRecord(self.in_pspec.width, False)
375 print("a1", a1.width, a1.rmw, a1.e_width, a1.e_start, a1.e_end)
376 m.submodules.sc_decode_a = a1 = FPNumDecode(None, a1)
377 m.d.comb += a1.v.eq(self.i.a)
378 z1 = self.o.z
379 print("z1", z1.width, z1.rmw, z1.e_width, z1.e_start, z1.e_end)
380
381 me = a1.rmw
382 ms = a1.rmw - self.o.z.rmw
383 print("ms-me", ms, me)
384
385 # intermediaries
386 exp_sub_n126 = Signal((a1.e_width, True), reset_less=True)
387 exp_gt127 = Signal(reset_less=True)
388 # constants from z1, at the bit-width of a1.
389 N126 = Const(z1.fp.N126.value, (a1.e_width, True))
390 P127 = Const(z1.fp.P127.value, (a1.e_width, True))
391 m.d.comb += exp_sub_n126.eq(a1.e - N126)
392 m.d.comb += exp_gt127.eq(a1.e > P127)
393
394 # if a zero, return zero (signed)
395 with m.If(a1.exp_n127):
396 m.d.comb += self.o.z.zero(a1.s)
397 m.d.comb += self.o.out_do_z.eq(1)
398
399 # if a range outside z's min range (-126)
400 with m.Elif(exp_sub_n126 < 0):
401 m.d.comb += self.o.of.guard.eq(a1.m[ms-1])
402 m.d.comb += self.o.of.round_bit.eq(a1.m[ms-2])
403 m.d.comb += self.o.of.sticky.eq(a1.m[:ms-2].bool())
404 m.d.comb += self.o.of.m0.eq(a1.m[ms]) # bit of a1
405
406 m.d.comb += self.o.z.s.eq(a1.s)
407 m.d.comb += self.o.z.e.eq(a1.e)
408 m.d.comb += self.o.z.m.eq(a1.m[-self.o.z.rmw-1:])
409 m.d.comb += self.o.z.m[-1].eq(1)
410
411 # if a is inf return inf
412 with m.Elif(a1.is_inf):
413 m.d.comb += self.o.z.inf(a1.s)
414 m.d.comb += self.o.out_do_z.eq(1)
415
416 # if a is NaN return NaN
417 with m.Elif(a1.is_nan):
418 m.d.comb += self.o.z.nan(0)
419 m.d.comb += self.o.out_do_z.eq(1)
420
421 # if a mantissa greater than 127, return inf
422 with m.Elif(exp_gt127):
423 print("inf", self.o.z.inf(a1.s))
424 m.d.comb += self.o.z.inf(a1.s)
425 m.d.comb += self.o.out_do_z.eq(1)
426
427 # ok after all that, anything else should fit fine (whew)
428 with m.Else():
429 m.d.comb += self.o.of.guard.eq(a1.m[ms-1])
430 m.d.comb += self.o.of.round_bit.eq(a1.m[ms-2])
431 m.d.comb += self.o.of.sticky.eq(a1.m[:ms-2].bool())
432 m.d.comb += self.o.of.m0.eq(a1.m[ms]) # bit of a1
433
434 # XXX TODO: this is basically duplicating FPRoundMod. hmmm...
435 print("alen", a1.e_start, z1.fp.N126, N126)
436 print("m1", self.o.z.rmw, a1.m[-self.o.z.rmw-1:])
437 mo = Signal(self.o.z.m_width-1)
438 m.d.comb += mo.eq(a1.m[ms:me])
439 with m.If(self.o.of.roundz):
440 with m.If((~mo == 0)): # all 1s
441 m.d.comb += self.o.z.create(a1.s, a1.e+1, mo+1)
442 with m.Else():
443 m.d.comb += self.o.z.create(a1.s, a1.e, mo+1)
444 with m.Else():
445 m.d.comb += self.o.z.create(a1.s, a1.e, a1.m[-self.o.z.rmw-1:])
446 m.d.comb += self.o.out_do_z.eq(1)
447
448 # copy the context (muxid, operator)
449 m.d.comb += self.o.oz.eq(self.o.z.v)
450 m.d.comb += self.o.ctx.eq(self.i.ctx)
451
452 return m
453
454
455 class FPCVTIntToFloat(FPState):
456 """ Up-conversion
457 """
458
459 def __init__(self, in_width, out_width, id_wid):
460 FPState.__init__(self, "inttofloat")
461 self.mod = FPCVTIntToFloatMod(in_width, out_width)
462 self.out_z = self.mod.ospec()
463 self.out_do_z = Signal(reset_less=True)
464
465 def setup(self, m, i):
466 """ links module to inputs and outputs
467 """
468 self.mod.setup(m, i, self.out_do_z)
469 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
470 m.d.sync += self.out_z.ctx.eq(self.mod.o.ctx) # (and context)
471
472 def action(self, m):
473 self.idsync(m)
474 with m.If(self.out_do_z):
475 m.next = "put_z"
476 with m.Else():
477 m.next = "denormalise"
478
479
480 class FPCVTUpConvert(FPState):
481 """ Up-conversion
482 """
483
484 def __init__(self, in_width, out_width, id_wid):
485 FPState.__init__(self, "upconvert")
486 self.mod = FPCVTUpConvertMod(in_width, out_width)
487 self.out_z = self.mod.ospec()
488 self.out_do_z = Signal(reset_less=True)
489
490 def setup(self, m, i):
491 """ links module to inputs and outputs
492 """
493 self.mod.setup(m, i, self.out_do_z)
494 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
495 m.d.sync += self.out_z.ctx.eq(self.mod.o.ctx) # (and context)
496
497 def action(self, m):
498 self.idsync(m)
499 with m.If(self.out_do_z):
500 m.next = "put_z"
501 with m.Else():
502 m.next = "denormalise"
503
504
505 class FPCVTDownConvert(FPState):
506 """ special cases: NaNs, infs, zeros, denormalised
507 """
508
509 def __init__(self, in_width, out_width, id_wid):
510 FPState.__init__(self, "special_cases")
511 self.mod = FPCVTDownConvertMod(in_width, out_width)
512 self.out_z = self.mod.ospec()
513 self.out_do_z = Signal(reset_less=True)
514
515 def setup(self, m, i):
516 """ links module to inputs and outputs
517 """
518 self.mod.setup(m, i, self.out_do_z)
519 m.d.sync += self.out_z.v.eq(self.mod.out_z.v) # only take the output
520 m.d.sync += self.out_z.ctx.eq(self.mod.o.ctx) # (and context)
521
522 def action(self, m):
523 self.idsync(m)
524 with m.If(self.out_do_z):
525 m.next = "put_z"
526 with m.Else():
527 m.next = "denormalise"
528
529
530 class FPCVTIntToFloatDeNorm(FPState, SimpleHandshake):
531 """ Upconvert
532 """
533
534 def __init__(self, in_pspec, out_pspec):
535 FPState.__init__(self, "inttofloat")
536 sc = FPCVTIntToFloatMod(in_pspec, out_pspec)
537 SimpleHandshake.__init__(self, sc)
538 self.out = self.ospec(None)
539
540
541 class FPCVTUpConvertDeNorm(FPState, SimpleHandshake):
542 """ Upconvert
543 """
544
545 def __init__(self, in_pspec, out_pspec):
546 FPState.__init__(self, "upconvert")
547 sc = FPCVTUpConvertMod(in_pspec, out_pspec)
548 SimpleHandshake.__init__(self, sc)
549 self.out = self.ospec(None)
550
551
552 class FPCVTDownConvertDeNorm(FPState, SimpleHandshake):
553 """ downconvert
554 """
555
556 def __init__(self, in_pspec, out_pspec):
557 FPState.__init__(self, "downconvert")
558 sc = FPCVTDownConvertMod(in_pspec, out_pspec)
559 SimpleHandshake.__init__(self, sc)
560 self.out = self.ospec(None)
561
562
563 class FPCVTIntBasePipe(ControlBase):
564 def __init__(self, in_pspec, out_pspec):
565 ControlBase.__init__(self)
566 self.pipe1 = FPCVTIntToFloatDeNorm(in_pspec, out_pspec)
567 self.pipe2 = FPNormToPack(out_pspec, e_extra=True)
568
569 self._eqs = self.connect([self.pipe1, self.pipe2])
570
571 def elaborate(self, platform):
572 m = ControlBase.elaborate(self, platform)
573 m.submodules.toint = self.pipe1
574 m.submodules.normpack = self.pipe2
575 m.d.comb += self._eqs
576 return m
577
578
579 class FPCVTUpBasePipe(ControlBase):
580 def __init__(self, in_pspec, out_pspec):
581 ControlBase.__init__(self)
582 self.pipe1 = FPCVTUpConvertDeNorm(in_pspec, out_pspec)
583 self.pipe2 = FPNormToPack(out_pspec, e_extra=False)
584
585 self._eqs = self.connect([self.pipe1, self.pipe2])
586
587 def elaborate(self, platform):
588 m = ControlBase.elaborate(self, platform)
589 m.submodules.up = self.pipe1
590 m.submodules.normpack = self.pipe2
591 m.d.comb += self._eqs
592 return m
593
594
595 class FPCVTDownBasePipe(ControlBase):
596 def __init__(self, in_pspec, out_pspec):
597 ControlBase.__init__(self)
598 self.pipe1 = FPCVTDownConvertDeNorm(in_pspec, out_pspec)
599 self.pipe2 = FPNormToPack(out_pspec, e_extra=True)
600
601 self._eqs = self.connect([self.pipe1, self.pipe2])
602
603 def elaborate(self, platform):
604 m = ControlBase.elaborate(self, platform)
605 m.submodules.down = self.pipe1
606 m.submodules.normpack = self.pipe2
607 m.d.comb += self._eqs
608 return m
609
610
611 class FPCVTIntMuxInOut(ReservationStations):
612 """ Reservation-Station version of FPCVT int-to-float pipeline.
613
614 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
615 * 2-stage multiplier pipeline
616 * fan-out on outputs (an array of FPPackData: z,mid)
617
618 Fan-in and Fan-out are combinatorial.
619 """
620
621 def __init__(self, in_width, out_width, num_rows, op_wid=0):
622 self.op_wid = op_wid
623 self.id_wid = num_bits(in_width)
624 self.out_id_wid = num_bits(out_width)
625
626 self.in_pspec = PipelineSpec(in_width, self.id_wid, self.op_wid)
627 self.out_pspec = PipelineSpec(out_width, self.out_id_wid, op_wid)
628
629 self.alu = FPCVTIntBasePipe(self.in_pspec, self.out_pspec)
630 ReservationStations.__init__(self, num_rows)
631
632 def i_specfn(self):
633 return FPADDBaseData(self.in_pspec)
634
635 def o_specfn(self):
636 return FPPackData(self.out_pspec)
637
638
639 class FPCVTUpMuxInOut(ReservationStations):
640 """ Reservation-Station version of FPCVT up pipeline.
641
642 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
643 * 2-stage multiplier pipeline
644 * fan-out on outputs (an array of FPPackData: z,mid)
645
646 Fan-in and Fan-out are combinatorial.
647 """
648
649 def __init__(self, in_width, out_width, num_rows, op_wid=0):
650 self.op_wid = op_wid
651 self.id_wid = num_bits(in_width)
652 self.out_id_wid = num_bits(out_width)
653
654 self.in_pspec = PipelineSpec(in_width, self.id_wid, self.op_wid)
655 self.out_pspec = PipelineSpec(out_width, self.out_id_wid, op_wid)
656
657 self.alu = FPCVTUpBasePipe(self.in_pspec, self.out_pspec)
658 ReservationStations.__init__(self, num_rows)
659
660 def i_specfn(self):
661 return FPADDBaseData(self.in_pspec)
662
663 def o_specfn(self):
664 return FPPackData(self.out_pspec)
665
666
667 class FPCVTDownMuxInOut(ReservationStations):
668 """ Reservation-Station version of FPCVT pipeline.
669
670 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
671 * 2-stage multiplier pipeline
672 * fan-out on outputs (an array of FPPackData: z,mid)
673
674 Fan-in and Fan-out are combinatorial.
675 """
676
677 def __init__(self, in_width, out_width, num_rows, op_wid=0):
678 self.op_wid = op_wid
679 self.id_wid = num_bits(in_width)
680 self.out_id_wid = num_bits(out_width)
681
682 self.in_pspec = PipelineSpec(in_width, self.id_wid, self.op_wid)
683 self.out_pspec = PipelineSpec(out_width, self.out_id_wid, op_wid)
684
685 self.alu = FPCVTDownBasePipe(self.in_pspec, self.out_pspec)
686 ReservationStations.__init__(self, num_rows)
687
688 def i_specfn(self):
689 return FPADDBaseData(self.in_pspec)
690
691 def o_specfn(self):
692 return FPPackData(self.out_pspec)