e8920833ce2d60327500d565a2b57d8032e201ff
[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 bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
7 """
8
9 from nmigen import Module, Signal, Cat, Elaboratable, Const, Mux
10 from nmigen.cli import main, verilog
11
12 from ieee754.fpcommon.fpbase import FPNumBaseRecord
13 from ieee754.fpcommon.fpbase import FPState
14 from ieee754.fpcommon.denorm import FPSCData
15 from ieee754.fpcommon.getop import FPPipeContext
16 from ieee754.div_rem_sqrt_rsqrt.div_pipe import DivPipeInputData
17 from ieee754.div_rem_sqrt_rsqrt.core import DivPipeCoreOperation as DPCOp
18
19
20 class FPDivStage0Mod(Elaboratable):
21 """ DIV/SQRT/RSQRT "preparation" module.
22
23 adjusts mantissa and exponent (sqrt/rsqrt exponent must be even),
24 puts exponent (and sign) into data structures for passing through to
25 the end, and puts the (adjusted) mantissa into the processing engine.
26
27 no *actual* processing occurs here: it is *purely* preparation work.
28 """
29
30 def __init__(self, pspec):
31 self.pspec = pspec
32 self.i = self.ispec()
33 self.o = self.ospec()
34
35 def ispec(self):
36 return FPSCData(self.pspec, False)
37
38 def ospec(self):
39 return DivPipeInputData(self.pspec)
40
41 def process(self, i):
42 return self.o
43
44 def setup(self, m, i):
45 """ links module to inputs and outputs
46 """
47 m.submodules.div0 = self
48 m.d.comb += self.i.eq(i)
49
50 def elaborate(self, platform):
51 m = Module()
52 comb = m.d.comb
53
54 # mantissas start in the range [1.0, 2.0)
55
56 # intermediary temp signals
57 is_div = Signal(reset_less=True)
58 need_exp_adj = Signal(reset_less=True)
59
60 # "adjusted" - ``self.i.a.rmw`` fractional bits and 2 integer bits
61 adj_a_mw = self.i.a.rmw
62 adj_a_m = Signal(self.i.a.rmw + 2, reset_less=True)
63 adj_a_e = Signal((len(self.i.a.e), True), reset_less=True)
64
65 # adjust (shift) the exponent so that it is even, but only for [r]sqrt
66 comb += [is_div.eq(self.i.ctx.op == int(DPCOp.UDivRem)),
67 need_exp_adj.eq(~is_div & self.i.a.e[0]), # even? !div? adjust
68 adj_a_m.eq(self.i.a.m << need_exp_adj),
69 adj_a_e.eq(self.i.a.e - need_exp_adj)]
70
71 # adj_a_m now in the range [1.0, 4.0) for sqrt/rsqrt
72 # and [1.0, 2.0) for div
73
74 fw = self.pspec.core_config.fract_width
75 divr_rad = Signal(len(self.o.divisor_radicand), reset_less=True)
76
77 # real mantissa fractional widths
78 a_mw = self.i.a.rmw
79 b_mw = self.i.b.rmw
80
81 comb += [self.o.dividend.eq(self.i.a.m << (fw*2 - a_mw)),
82 divr_rad.eq(Mux(is_div, self.i.b.m << (fw - b_mw),
83 adj_a_m << (fw - adj_a_mw))),
84 self.o.divisor_radicand.eq(divr_rad),
85 ]
86
87 # set default since it's not always set; non-zero value for debugging
88 comb += self.o.operation.eq(1)
89
90 with m.If(~self.i.out_do_z):
91 # DIV
92 with m.If(self.i.ctx.op == int(DPCOp.UDivRem)):
93 comb += [self.o.z.e.eq(self.i.a.e - self.i.b.e),
94 self.o.z.s.eq(self.i.a.s ^ self.i.b.s),
95 self.o.operation.eq(int(DPCOp.UDivRem))
96 ]
97
98 # SQRT
99 with m.Elif(self.i.ctx.op == int(DPCOp.SqrtRem)):
100 comb += [self.o.z.e.eq(adj_a_e >> 1),
101 self.o.z.s.eq(self.i.a.s),
102 self.o.operation.eq(int(DPCOp.SqrtRem))
103 ]
104
105 # RSQRT
106 with m.Elif(self.i.ctx.op == int(DPCOp.RSqrtRem)):
107 comb += [self.o.z.e.eq(-(adj_a_e >> 1)),
108 self.o.z.s.eq(self.i.a.s),
109 self.o.operation.eq(int(DPCOp.RSqrtRem))
110 ]
111
112 # these are required and must not be touched
113 comb += self.o.oz.eq(self.i.oz)
114 comb += self.o.out_do_z.eq(self.i.out_do_z)
115 comb += self.o.ctx.eq(self.i.ctx)
116
117 return m
118
119
120 class FPDivStage0(FPState):
121 """ First stage of div.
122 """
123
124 def __init__(self, pspec):
125 FPState.__init__(self, "divider_0")
126 self.mod = FPDivStage0Mod(pspec)
127 self.o = self.mod.ospec()
128
129 def setup(self, m, i):
130 """ links module to inputs and outputs
131 """
132 self.mod.setup(m, i)
133
134 # NOTE: these could be done as combinatorial (merge div0+div1)
135 m.d.sync += self.o.eq(self.mod.o)
136
137 def action(self, m):
138 m.next = "divider_1"