add copyright / bugreport notice
[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, Elaboratable, Cat
13 from nmigen.cli import main, verilog
14
15 from ieee754.fpcommon.fpbase import FPState
16 from ieee754.fpcommon.postcalc import FPAddStage1Data
17 from ieee754.div_rem_sqrt_rsqrt.div_pipe import DivPipeOutputData
18
19
20 class FPDivStage2Mod(FPState, Elaboratable):
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 self.pspec = pspec
29 self.i = self.ispec()
30 self.o = self.ospec()
31
32 def ispec(self):
33 return DivPipeOutputData(self.pspec) # Q/Rem in...
34
35 def ospec(self):
36 # XXX REQUIRED. MUST NOT BE CHANGED. this is the format
37 # required for ongoing processing (normalisation, correction etc.)
38 return FPAddStage1Data(self.pspec) # out to post-process
39
40 def process(self, i):
41 return self.o
42
43 def setup(self, m, i):
44 """ links module to inputs and outputs
45 """
46 m.submodules.div1 = self
47 m.d.comb += self.i.eq(i)
48
49 def elaborate(self, platform):
50 m = Module()
51 comb = m.d.comb
52
53 # copies sign and exponent and mantissa (mantissa and exponent to be
54 # overridden below)
55 comb += self.o.z.eq(self.i.z)
56
57 # Operations and input/output mantissa ranges:
58 # fdiv:
59 # dividend [1.0, 2.0)
60 # divisor [1.0, 2.0)
61 # result (0.5, 2.0)
62 #
63 # fsqrt:
64 # radicand [1.0, 4.0)
65 # result [1.0, 2.0)
66 #
67 # frsqrt:
68 # radicand [1.0, 4.0)
69 # result (0.5, 1.0]
70
71 with m.If(~self.i.out_do_z):
72 # following section partially normalizes result to range [1.0, 2.0)
73 fw = self.pspec.core_config.fract_width
74 qr_int_part = Signal(2, reset_less=True)
75 comb += qr_int_part.eq(self.i.quotient_root[fw:][:2])
76
77 need_shift = Signal(reset_less=True)
78
79 # shift left when result is less than 2.0 since result_m has 1 more
80 # fraction bit, making assigning to it the equivalent of
81 # dividing by 2.
82 # this all comes out to:
83 # if quotient_root < 2.0:
84 # # div by 2 from assign; mul by 2 from shift left
85 # result = (quotient_root * 2) / 2
86 # else:
87 # # div by 2 from assign
88 # result = quotient_root / 2
89 comb += need_shift.eq(qr_int_part < 2)
90
91 # one extra fraction bit to accommodate the result when not
92 # shifting and for effective div by 2
93 result_m_fract_width = fw + 1
94 # 1 integer bit since the numbers are less than 2.0
95 result_m = Signal(1 + result_m_fract_width, reset_less=True)
96 result_e = Signal(len(self.i.z.e), reset_less=True)
97
98 comb += [
99 result_m.eq(self.i.quotient_root << need_shift),
100 result_e.eq(self.i.z.e + (1 - need_shift))
101 ]
102
103 # result_m is now in the range [1.0, 2.0)
104 comb += [
105 self.o.z.m.eq(result_m[3:]), # mantissa
106 self.o.of.m0.eq(result_m[3]), # copy of mantissa LSB
107 self.o.of.guard.eq(result_m[2]), # guard
108 self.o.of.round_bit.eq(result_m[1]), # round
109 self.o.of.sticky.eq(result_m[0] | self.i.remainder.bool()),
110 self.o.z.e.eq(result_e),
111 ]
112
113 comb += self.o.out_do_z.eq(self.i.out_do_z)
114 comb += self.o.oz.eq(self.i.oz)
115 comb += self.o.ctx.eq(self.i.ctx)
116
117 return m
118
119
120 class FPDivStage2(FPState):
121
122 def __init__(self, pspec):
123 FPState.__init__(self, "divider_1")
124 self.mod = FPDivStage2Mod(pspec)
125 self.out_z = FPNumBaseRecord(pspec, False)
126 self.out_of = Overflow()
127 self.norm_stb = Signal()
128
129 def setup(self, m, i):
130 """ links module to inputs and outputs
131 """
132 self.mod.setup(m, i)
133
134 m.d.sync += self.norm_stb.eq(0) # sets to zero when not in div1 state
135
136 m.d.sync += self.out_of.eq(self.mod.out_of)
137 m.d.sync += self.out_z.eq(self.mod.out_z)
138 m.d.sync += self.norm_stb.eq(1)
139
140 def action(self, m):
141 m.next = "normalise_1"