config/setup/imports
[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.submodules.div1_out_overflow = self.o.of
39
40 m.d.comb += self.i.eq(i)
41
42 def elaborate(self, platform):
43 m = Module()
44
45 # copies sign and exponent and mantissa (mantissa to be overridden
46 # below)
47 m.d.comb += self.o.z.eq(self.i.z)
48
49 # TODO: this is "phase 3" of divide (the very end of the pipeline)
50 # takes the Q and R data (whatever) and performs
51 # last-stage guard/round/sticky and copies mantissa into z.
52 # post-processing stages take care of things from that point.
53
54 # NOTE: this phase does NOT do ACTUAL DIV processing, it ONLY
55 # does "conversion" *out* of the Q/REM last stage
56
57 # NOTE: see FPDivStage0Mod comment. the quotient is assumed
58 # to be in the range 0.499999-recurring to 1.999998. normalisation
59 # will take care of that, *however*, it *might* be necessary to
60 # subtract 1 from the exponent and have one extra bit in the
61 # mantissa to compensate. this is pretty much exactly what's
62 # done in FPMUL, due to 0.5-0.9999 * 0.5-0.9999 also producing
63 # values within the range 0.5 to 1.999998
64
65 with m.If(~self.i.out_do_z):
66 mw = self.o.z.m_width
67 # TODO: compensate for answer being in range 0.49999 to 1.99998
68 p = Signal(len(self.i.quotient_root), reset_less=True)
69 with m.If(self.i.quotient_root[-1]):
70 m.d.comb += p.eq(self.i.quotient_root)
71 with m.Else():
72 # get 1 bit of extra accuracy if the mantissa top bit is zero
73 m.d.comb += p.eq(self.i.quotient_root<<1)
74 m.d.comb += self.o.z.e.eq(self.i.z.e-1)
75
76 # TODO: use p here instead of quotient_root, direct.
77 # XXX what to do about remainder? shift that as well?
78 # hmm, how about concatenate remainder and quotient...
79 m.d.comb += [
80 self.o.z.m.eq(self.i.quotient_root[mw+2:]),
81 self.o.of.m0.eq(self.i.quotient_root[mw+2]), # copy of LSB
82 self.o.of.guard.eq(self.i.quotient_root[mw+1]),
83 self.o.of.round_bit.eq(self.i.quotient_root[mw]),
84 self.o.of.sticky.eq(Cat(self.i.remainder,
85 self.i.quotient_root[: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