37583b0f289e049267aed53f1d393a95f6662a0e
[ieee754fpu.git] / src / ieee754 / fpdiv / div0.py
1 """IEEE754 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
13 from nmigen import Module, Signal, Cat, Elaboratable, Const, Mux
14 from nmigen.cli import main, verilog
15
16 from nmutil.pipemodbase import PipeModBase
17 from ieee754.fpcommon.fpbase import FPNumBaseRecord
18 from ieee754.fpcommon.denorm import FPSCData
19 from ieee754.fpcommon.getop import FPPipeContext
20 from ieee754.div_rem_sqrt_rsqrt.div_pipe import DivPipeInputData
21 from ieee754.div_rem_sqrt_rsqrt.core import DivPipeCoreOperation as DPCOp
22
23
24 class FPDivStage0Mod(PipeModBase):
25 """ DIV/SQRT/RSQRT "preparation" module.
26
27 adjusts mantissa and exponent (sqrt/rsqrt exponent must be even),
28 puts exponent (and sign) into data structures for passing through to
29 the end, and puts the (adjusted) mantissa into the processing engine.
30
31 no *actual* processing occurs here: it is *purely* preparation work.
32 """
33 def __init__(self, pspec):
34 super().__init__(pspec, "div0")
35
36 def ispec(self):
37 return FPSCData(self.pspec, False)
38
39 def ospec(self):
40 return DivPipeInputData(self.pspec)
41
42 def elaborate(self, platform):
43 m = Module()
44 comb = m.d.comb
45
46 # mantissas start in the range [1.0, 2.0)
47
48 # intermediary temp signals
49 is_div = Signal(reset_less=True)
50 need_exp_adj = Signal(reset_less=True)
51
52 # "adjusted" - ``self.i.a.rmw`` fractional bits and 2 integer bits
53 adj_a_mw = self.i.a.rmw
54 adj_a_m = Signal(self.i.a.rmw + 2, reset_less=True)
55 adj_a_e = Signal((len(self.i.a.e), True), reset_less=True)
56
57 # adjust (shift) the exponent so that it is even, but only for [r]sqrt
58 comb += [is_div.eq(self.i.ctx.op == int(DPCOp.UDivRem)),
59 need_exp_adj.eq(~is_div & self.i.a.e[0]), # even? !div? adjust
60 adj_a_m.eq(self.i.a.m << need_exp_adj),
61 adj_a_e.eq(self.i.a.e - need_exp_adj)]
62
63 # adj_a_m now in the range [1.0, 4.0) for sqrt/rsqrt
64 # and [1.0, 2.0) for div
65
66 fw = self.pspec.core_config.fract_width
67 divr_rad = Signal(len(self.o.divisor_radicand), reset_less=True)
68
69 # real mantissa fractional widths
70 a_mw = self.i.a.rmw
71 b_mw = self.i.b.rmw
72
73 comb += [self.o.dividend.eq(self.i.a.m << (fw*2 - a_mw)),
74 divr_rad.eq(Mux(is_div, self.i.b.m << (fw - b_mw),
75 adj_a_m << (fw - adj_a_mw))),
76 self.o.divisor_radicand.eq(divr_rad),
77 ]
78
79 with m.If(~self.i.out_do_z):
80 # DIV
81 with m.If(self.i.ctx.op == int(DPCOp.UDivRem)):
82 # DIV: subtract exponents, XOR sign
83 comb += [self.o.z.e.eq(self.i.a.e - self.i.b.e),
84 self.o.z.s.eq(self.i.a.s ^ self.i.b.s),
85 self.o.operation.eq(int(DPCOp.UDivRem))
86 ]
87 # SQRT
88 with m.Elif(self.i.ctx.op == int(DPCOp.SqrtRem)):
89 # SQRT: sign is the same, [adjusted] exponent is halved
90 comb += [self.o.z.e.eq(adj_a_e >> 1), # halve
91 self.o.z.s.eq(self.i.a.s),
92 self.o.operation.eq(int(DPCOp.SqrtRem))
93 ]
94 # RSQRT
95 with m.Elif(self.i.ctx.op == int(DPCOp.RSqrtRem)):
96 # RSQRT: sign same, [adjusted] exponent halved and inverted
97 comb += [self.o.z.e.eq(-(adj_a_e >> 1)), # NEGATE and halve
98 self.o.z.s.eq(self.i.a.s),
99 self.o.operation.eq(int(DPCOp.RSqrtRem))
100 ]
101
102 # these are required and must not be touched
103 comb += self.o.oz.eq(self.i.oz)
104 comb += self.o.out_do_z.eq(self.i.out_do_z)
105 comb += self.o.ctx.eq(self.i.ctx)
106
107 return m
108
109