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