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