a92043c3117126dc8b5c91969dff9622005dbf58
[ieee754fpu.git] / src / ieee754 / fpdiv / div2.py
1 """IEEE Floating Point Divider
2
3 Relevant bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
4 """
5
6 from nmigen import Module, Signal, Elaboratable
7 from nmigen.cli import main, verilog
8
9 from ieee754.fpcommon.fpbase import FPState
10 from ieee754.fpcommon.postcalc import FPAddStage1Data
11
12
13 class FPDivStage2Mod(FPState, Elaboratable):
14 """ Second stage of div: preparation for normalisation.
15 """
16
17 def __init__(self, pspec):
18 self.pspec = pspec
19 self.i = self.ispec()
20 self.o = self.ospec()
21
22 def ispec(self):
23 return DivPipeOutputData(self.pspec) # Q/Rem in...
24
25 def ospec(self):
26 # XXX REQUIRED. MUST NOT BE CHANGED. this is the format
27 # required for ongoing processing (normalisation, correction etc.)
28 return FPAddStage1Data(self.pspec) # out to post-process
29
30 def process(self, i):
31 return self.o
32
33 def setup(self, m, i):
34 """ links module to inputs and outputs
35 """
36 m.submodules.div1 = self
37 #m.submodules.div1_out_overflow = self.o.of
38
39 m.d.comb += self.i.eq(i)
40
41 def elaborate(self, platform):
42 m = Module()
43
44 # copies sign and exponent and mantissa (mantissa to be overridden
45 # below)
46 m.d.comb += self.o.z.eq(self.i.z)
47
48 # TODO: this is "phase 3" of divide (the very end of the pipeline)
49 # takes the Q and R data (whatever) and performs
50 # last-stage guard/round/sticky and copies mantissa into z.
51 # post-processing stages take care of things from that point.
52
53 # NOTE: this phase does NOT do ACTUAL DIV processing, it ONLY
54 # does "conversion" *out* of the Q/REM last stage
55
56 # NOTE: see FPDivStage0Mod comment. the quotient is assumed
57 # to be in the range 0.499999-recurring to 1.999998. normalisation
58 # will take care of that, *however*, it *might* be necessary to
59 # subtract 1 from the exponent and have one extra bit in the
60 # mantissa to compensate. this is pretty much exactly what's
61 # done in FPMUL, due to 0.5-0.9999 * 0.5-0.9999 also producing
62 # values within the range 0.5 to 1.999998
63
64 with m.If(~self.i.out_do_z):
65 mw = self.o.z.m_width
66 # TODO: compensate for answer being in range 0.49999 to 1.99998
67 p = Signal(len(self.i.quotient_root), reset_less=True)
68 with m.If(self.i.quotient_root[-1]):
69 m.d.comb += p.eq(self.i.quotient_root)
70 with m.Else():
71 # get 1 bit of extra accuracy if the mantissa top bit is zero
72 m.d.comb += p.eq(self.i.quotient_root<<1)
73 m.d.comb += self.o.z.e.eq(self.i.z.e-1)
74
75 # TODO: use p here instead of quotient_root, direct.
76 # XXX what to do about remainder? shift that as well?
77 # hmm, how about concatenate remainder and quotient...
78 m.d.comb += [
79 self.o.z.m.eq(self.i.quotient_root[mw+2:]),
80 self.o.of.m0.eq(self.i.quotient_root[mw+2]), # copy of LSB
81 self.o.of.guard.eq(self.i.quotient_root[mw+1]),
82 self.o.of.round_bit.eq(self.i.quotient_root[mw]),
83 self.o.of.sticky.eq(Cat(self.i.remainder,
84 self.i.quotient_root[:mw]).bool())
85 ]
86
87 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
88 m.d.comb += self.o.oz.eq(self.i.oz)
89 m.d.comb += self.o.ctx.eq(self.i.ctx)
90
91 return m
92
93
94 class FPDivStage2(FPState):
95
96 def __init__(self, pspec):
97 FPState.__init__(self, "divider_1")
98 self.mod = FPDivStage2Mod(pspec)
99 self.out_z = FPNumBaseRecord(pspec, False)
100 self.out_of = Overflow()
101 self.norm_stb = Signal()
102
103 def setup(self, m, i):
104 """ links module to inputs and outputs
105 """
106 self.mod.setup(m, i)
107
108 m.d.sync += self.norm_stb.eq(0) # sets to zero when not in div1 state
109
110 m.d.sync += self.out_of.eq(self.mod.out_of)
111 m.d.sync += self.out_z.eq(self.mod.out_z)
112 m.d.sync += self.norm_stb.eq(1)
113
114 def action(self, m):
115 m.next = "normalise_1"
116