get fpdiv/fsqrt/frsqrt up and running
[ieee754fpu.git] / src / ieee754 / fpdiv / div0.py
1 """IEEE754 Floating Point Divider
2
3 Relevant bugreport: http://bugs.libre-riscv.org/show_bug.cgi?id=99
4 """
5
6 from nmigen import Module, Signal, Cat, Elaboratable, Const, Mux
7 from nmigen.cli import main, verilog
8
9 from ieee754.fpcommon.fpbase import (FPNumBaseRecord, Overflow)
10 from ieee754.fpcommon.fpbase import FPState
11 from ieee754.fpcommon.denorm import FPSCData
12 from ieee754.fpcommon.getop import FPPipeContext
13 from ieee754.div_rem_sqrt_rsqrt.div_pipe import DivPipeInputData
14 from ieee754.div_rem_sqrt_rsqrt.core import DivPipeCoreOperation as DPCOp
15
16
17 class FPDivStage0Mod(Elaboratable):
18
19 def __init__(self, pspec):
20 self.pspec = pspec
21 self.i = self.ispec()
22 self.o = self.ospec()
23
24 def ispec(self):
25 return FPSCData(self.pspec, False)
26
27 def ospec(self):
28 return DivPipeInputData(self.pspec)
29
30 def process(self, i):
31 return self.o
32
33 def setup(self, m, i):
34 """ links module to inputs and outputs
35 """
36 m.submodules.div0 = self
37 m.d.comb += self.i.eq(i)
38
39 def elaborate(self, platform):
40 m = Module()
41
42 # XXX TODO, actual DIV code here. this class would be
43 # "step one" which takes the pre-normalised data (see ispec) and
44 # *begins* the processing phase (enters the massive DIV
45 # pipeline chain) - see ospec.
46
47 # INPUT SPEC: FPSCData
48 # OUTPUT SPEC: DivPipeInputData
49
50 # NOTE: this stage does *NOT* do *ACTUAL* DIV processing,
51 # it is PURELY the *ENTRY* point into the chain, performing
52 # "preparation" work.
53
54 # mantissas start in the range [1.0, 2.0)
55
56 is_div = Signal(reset_less=True)
57 need_exp_adj = Signal(reset_less=True)
58
59 # ``self.i.a.rmw`` fractional bits and 2 integer bits
60 adj_a_m_fract_width = self.i.a.rmw
61 adj_a_m = Signal(self.i.a.rmw + 2, reset_less=True)
62
63 adj_a_e = Signal((len(self.i.a.e), True), reset_less=True)
64
65 m.d.comb += [is_div.eq(self.i.ctx.op == int(DPCOp.UDivRem)),
66 need_exp_adj.eq(~is_div & self.i.a.e[0]),
67 adj_a_m.eq(self.i.a.m << need_exp_adj),
68 adj_a_e.eq(self.i.a.e - need_exp_adj)]
69
70 # adj_a_m now in the range [1.0, 4.0) for sqrt/rsqrt
71 # and [1.0, 2.0) for div
72
73 dividend_fract_width = self.pspec.core_config.fract_width * 2
74 dividend = Signal(len(self.o.dividend),
75 reset_less=True)
76
77 divr_rad_fract_width = self.pspec.core_config.fract_width
78 divr_rad = Signal(len(self.o.divisor_radicand),
79 reset_less=True)
80
81 a_m_fract_width = self.i.a.rmw
82 b_m_fract_width = self.i.b.rmw
83
84 m.d.comb += [
85 dividend.eq(self.i.a.m << (
86 dividend_fract_width - a_m_fract_width)),
87 divr_rad.eq(Mux(is_div,
88 self.i.b.m << (
89 divr_rad_fract_width - b_m_fract_width),
90 adj_a_m << (
91 divr_rad_fract_width - adj_a_m_fract_width))),
92 ]
93
94 m.d.comb += [
95 self.o.dividend.eq(dividend),
96 self.o.divisor_radicand.eq(divr_rad),
97 ]
98
99 # set default since it's not always set; non-zero value for debugging
100 m.d.comb += self.o.operation.eq(1)
101
102 with m.If(~self.i.out_do_z):
103 # DIV
104 with m.If(self.i.ctx.op == int(DPCOp.UDivRem)):
105 m.d.comb += [self.o.z.e.eq(self.i.a.e - self.i.b.e),
106 self.o.z.s.eq(self.i.a.s ^ self.i.b.s),
107 self.o.operation.eq(int(DPCOp.UDivRem))
108 ]
109
110 # SQRT
111 with m.Elif(self.i.ctx.op == int(DPCOp.SqrtRem)):
112 m.d.comb += [self.o.z.e.eq(adj_a_e >> 1),
113 self.o.z.s.eq(self.i.a.s),
114 self.o.operation.eq(int(DPCOp.SqrtRem))
115 ]
116
117 # RSQRT
118 with m.Elif(self.i.ctx.op == int(DPCOp.RSqrtRem)):
119 m.d.comb += [self.o.z.e.eq(-(adj_a_e >> 1)),
120 self.o.z.s.eq(self.i.a.s),
121 self.o.operation.eq(int(DPCOp.RSqrtRem))
122 ]
123
124 # these are required and must not be touched
125 m.d.comb += self.o.oz.eq(self.i.oz)
126 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
127 m.d.comb += self.o.ctx.eq(self.i.ctx)
128
129 return m
130
131
132 class FPDivStage0(FPState):
133 """ First stage of div.
134 """
135
136 def __init__(self, pspec):
137 FPState.__init__(self, "divider_0")
138 self.mod = FPDivStage0Mod(pspec)
139 self.o = self.mod.ospec()
140
141 def setup(self, m, i):
142 """ links module to inputs and outputs
143 """
144 self.mod.setup(m, i)
145
146 # NOTE: these could be done as combinatorial (merge div0+div1)
147 m.d.sync += self.o.eq(self.mod.o)
148
149 def action(self, m):
150 m.next = "divider_1"