remove m.If/Elif in fpdiv sqrt, replace with Mux
[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 PipeModBase
16 from ieee754.fpcommon.postcalc import FPPostCalcData
17 from ieee754.div_rem_sqrt_rsqrt.div_pipe import DivPipeOutputData
18
19
20 class FPDivPostToFPFormat(PipeModBase):
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, "post_to_fp_fmt")
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 FPPostCalcData(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 # following section partially normalizes result to range [1.0, 2.0)
61 fw = self.pspec.core_config.fract_width
62 qr_int_part = Signal(2, reset_less=True)
63 comb += qr_int_part.eq(self.i.quotient_root[fw:][:2])
64
65 need_shift = Signal(reset_less=True)
66
67 # shift left when result is less than 2.0 since result_m has 1 more
68 # fraction bit, making assigning to it the equivalent of
69 # dividing by 2.
70 # this all comes out to:
71 # if quotient_root < 2.0:
72 # # div by 2 from assign; mul by 2 from shift left
73 # result = (quotient_root * 2) / 2
74 # else:
75 # # div by 2 from assign
76 # result = quotient_root / 2
77 comb += need_shift.eq(qr_int_part < 2)
78
79 # one extra fraction bit to accommodate the result when not
80 # shifting and for effective div by 2
81 result_m_fract_width = fw + 1
82 # 1 integer bit since the numbers are less than 2.0
83 result_m = Signal(1 + result_m_fract_width, reset_less=True)
84 result_e = Signal(len(self.i.z.e), reset_less=True)
85
86 comb += [
87 result_m.eq(self.i.quotient_root << need_shift),
88 result_e.eq(self.i.z.e + (1 - need_shift))
89 ]
90
91 # result_m is now in the range [1.0, 2.0)
92 comb += [
93 self.o.z.m.eq(result_m[3:]), # mantissa
94 self.o.of.m0.eq(result_m[3]), # copy of mantissa LSB
95 self.o.of.guard.eq(result_m[2]), # guard
96 self.o.of.round_bit.eq(result_m[1]), # round
97 self.o.of.sticky.eq(result_m[0] | self.i.remainder.bool()),
98 self.o.z.e.eq(result_e),
99 ]
100
101 # pass through context
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