resolve awful meta-class hacking (with thanks to jsbueno on stackexchange)
[ieee754fpu.git] / src / ieee754 / fpmul / mul1.py
1 # IEEE Floating Point Multiplier
2
3 from nmigen import Module, Signal, Elaboratable
4 from nmigen.cli import main, verilog
5
6 from ieee754.fpcommon.fpbase import FPState
7 from ieee754.fpcommon.postcalc import FPAddStage1Data
8 from .mul0 import FPMulStage0Data
9
10
11 class FPMulStage1Mod(FPState, Elaboratable):
12 """ Second stage of mul: preparation for normalisation.
13 """
14
15 def __init__(self, pspec):
16 self.pspec = pspec
17 self.i = self.ispec()
18 self.o = self.ospec()
19
20 def ispec(self):
21 return FPMulStage0Data(self.pspec)
22
23 def ospec(self):
24 return FPAddStage1Data(self.pspec)
25
26 def process(self, i):
27 return self.o
28
29 def setup(self, m, i):
30 """ links module to inputs and outputs
31 """
32 m.submodules.mul1 = self
33 m.d.comb += self.i.eq(i)
34
35 def elaborate(self, platform):
36 m = Module()
37 m.d.comb += self.o.z.eq(self.i.z)
38 with m.If(~self.i.out_do_z):
39 # results are in the range 0.25 to 0.999999999999
40 # sometimes the MSB will be zero, (0.5 * 0.5 = 0.25 which
41 # in binary is 0b010000) so to compensate for that we have
42 # to shift the mantissa up (and reduce the exponent by 1)
43 p = Signal(len(self.i.product), reset_less=True)
44 with m.If(self.i.product[-1]):
45 m.d.comb += p.eq(self.i.product)
46 with m.Else():
47 # get 1 bit of extra accuracy if the mantissa top bit is zero
48 m.d.comb += p.eq(self.i.product<<1)
49 m.d.comb += self.o.z.e.eq(self.i.z.e-1)
50
51 # top bits are mantissa, then guard and round, and the rest of
52 # the product is sticky
53 mw = self.o.z.m_width
54 m.d.comb += [
55 self.o.z.m.eq(p[mw+2:]), # mantissa
56 self.o.of.m0.eq(p[mw+2]), # copy of LSB
57 self.o.of.guard.eq(p[mw+1]), # guard
58 self.o.of.round_bit.eq(p[mw]), # round
59 self.o.of.sticky.eq(p[0:mw].bool()) # sticky
60 ]
61
62 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
63 m.d.comb += self.o.oz.eq(self.i.oz)
64 m.d.comb += self.o.ctx.eq(self.i.ctx)
65
66 return m
67
68
69 class FPMulStage1(FPState):
70
71 def __init__(self, pspec):
72 FPState.__init__(self, "multiply_1")
73 width = pspec.width
74 self.mod = FPMulStage1Mod(pspec)
75 self.out_z = FPNumBaseRecord(width, False)
76 self.norm_stb = Signal()
77
78 def setup(self, m, i):
79 """ links module to inputs and outputs
80 """
81 self.mod.setup(m, i)
82
83 m.d.sync += self.norm_stb.eq(0) # sets to zero when not in mul1 state
84
85 m.d.sync += self.out_z.eq(self.mod.out_z)
86 m.d.sync += self.norm_stb.eq(1)
87
88 def action(self, m):
89 m.next = "normalise_1"
90