move FPModBase and FPModBaseChain to nmutil
[ieee754fpu.git] / src / ieee754 / fpdiv / div2.py
1 """IEEE Floating Point Divider
2
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
4 Copyright (C) 2019 Jacob Lifshay
5
6 Relevant bugreports:
7 * http://bugs.libre-riscv.org/show_bug.cgi?id=99
8 * http://bugs.libre-riscv.org/show_bug.cgi?id=43
9 * http://bugs.libre-riscv.org/show_bug.cgi?id=44
10 """
11
12 from nmigen import Module, Signal, Cat
13 from nmigen.cli import main, verilog
14
15 from nmutil.pipemodbase import FPModBase
16 from ieee754.fpcommon.postcalc import FPAddStage1Data
17 from ieee754.div_rem_sqrt_rsqrt.div_pipe import DivPipeOutputData
18
19
20 class FPDivStage2Mod(FPModBase):
21 """ Last stage of div: preparation for normalisation.
22
23 NOTE: this phase does NOT do ACTUAL DIV processing, it ONLY
24 does "conversion" *out* of the Q/REM last stage
25 """
26
27 def __init__(self, pspec):
28 super().__init__(pspec, "div1")
29
30 def ispec(self):
31 return DivPipeOutputData(self.pspec) # Q/Rem in...
32
33 def ospec(self):
34 # XXX REQUIRED. MUST NOT BE CHANGED. this is the format
35 # required for ongoing processing (normalisation, correction etc.)
36 return FPAddStage1Data(self.pspec) # out to post-process
37
38 def elaborate(self, platform):
39 m = Module()
40 comb = m.d.comb
41
42 # copies sign and exponent and mantissa (mantissa and exponent to be
43 # overridden below)
44 comb += self.o.z.eq(self.i.z)
45
46 # Operations and input/output mantissa ranges:
47 # fdiv:
48 # dividend [1.0, 2.0)
49 # divisor [1.0, 2.0)
50 # result (0.5, 2.0)
51 #
52 # fsqrt:
53 # radicand [1.0, 4.0)
54 # result [1.0, 2.0)
55 #
56 # frsqrt:
57 # radicand [1.0, 4.0)
58 # result (0.5, 1.0]
59
60 with m.If(~self.i.out_do_z):
61 # following section partially normalizes result to range [1.0, 2.0)
62 fw = self.pspec.core_config.fract_width
63 qr_int_part = Signal(2, reset_less=True)
64 comb += qr_int_part.eq(self.i.quotient_root[fw:][:2])
65
66 need_shift = Signal(reset_less=True)
67
68 # shift left when result is less than 2.0 since result_m has 1 more
69 # fraction bit, making assigning to it the equivalent of
70 # dividing by 2.
71 # this all comes out to:
72 # if quotient_root < 2.0:
73 # # div by 2 from assign; mul by 2 from shift left
74 # result = (quotient_root * 2) / 2
75 # else:
76 # # div by 2 from assign
77 # result = quotient_root / 2
78 comb += need_shift.eq(qr_int_part < 2)
79
80 # one extra fraction bit to accommodate the result when not
81 # shifting and for effective div by 2
82 result_m_fract_width = fw + 1
83 # 1 integer bit since the numbers are less than 2.0
84 result_m = Signal(1 + result_m_fract_width, reset_less=True)
85 result_e = Signal(len(self.i.z.e), reset_less=True)
86
87 comb += [
88 result_m.eq(self.i.quotient_root << need_shift),
89 result_e.eq(self.i.z.e + (1 - need_shift))
90 ]
91
92 # result_m is now in the range [1.0, 2.0)
93 comb += [
94 self.o.z.m.eq(result_m[3:]), # mantissa
95 self.o.of.m0.eq(result_m[3]), # copy of mantissa LSB
96 self.o.of.guard.eq(result_m[2]), # guard
97 self.o.of.round_bit.eq(result_m[1]), # round
98 self.o.of.sticky.eq(result_m[0] | self.i.remainder.bool()),
99 self.o.z.e.eq(result_e),
100 ]
101
102 comb += self.o.out_do_z.eq(self.i.out_do_z)
103 comb += self.o.oz.eq(self.i.oz)
104 comb += self.o.ctx.eq(self.i.ctx)
105
106 return m
107
108