split out add stage 0 to separate module
[ieee754fpu.git] / src / add / fpadd / add0.py
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
3 # 2013-12-12
4
5 from nmigen import Module, Signal, Cat, Mux, Array, Const
6 from nmigen.lib.coding import PriorityEncoder
7 from nmigen.cli import main, verilog
8 from math import log
9
10 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPNumBase
11 from fpbase import MultiShiftRMerge, Trigger
12 from singlepipe import (ControlBase, StageChain, UnbufferedPipeline,
13 PassThroughStage)
14 from multipipe import CombMuxOutPipe
15 from multipipe import PriorityCombMuxInPipe
16
17 from fpbase import FPState, FPID
18 from fpcommon.denorm import FPSCData
19
20
21 class FPAddStage0Data:
22
23 def __init__(self, width, id_wid):
24 self.z = FPNumBase(width, False)
25 self.out_do_z = Signal(reset_less=True)
26 self.oz = Signal(width, reset_less=True)
27 self.tot = Signal(self.z.m_width + 4, reset_less=True)
28 self.mid = Signal(id_wid, reset_less=True)
29
30 def eq(self, i):
31 return [self.z.eq(i.z), self.out_do_z.eq(i.out_do_z), self.oz.eq(i.oz),
32 self.tot.eq(i.tot), self.mid.eq(i.mid)]
33
34
35 class FPAddStage0Mod:
36
37 def __init__(self, width, id_wid):
38 self.width = width
39 self.id_wid = id_wid
40 self.i = self.ispec()
41 self.o = self.ospec()
42
43 def ispec(self):
44 return FPSCData(self.width, self.id_wid)
45
46 def ospec(self):
47 return FPAddStage0Data(self.width, self.id_wid)
48
49 def process(self, i):
50 return self.o
51
52 def setup(self, m, i):
53 """ links module to inputs and outputs
54 """
55 m.submodules.add0 = self
56 m.d.comb += self.i.eq(i)
57
58 def elaborate(self, platform):
59 m = Module()
60 m.submodules.add0_in_a = self.i.a
61 m.submodules.add0_in_b = self.i.b
62 m.submodules.add0_out_z = self.o.z
63
64 # store intermediate tests (and zero-extended mantissas)
65 seq = Signal(reset_less=True)
66 mge = Signal(reset_less=True)
67 am0 = Signal(len(self.i.a.m)+1, reset_less=True)
68 bm0 = Signal(len(self.i.b.m)+1, reset_less=True)
69 m.d.comb += [seq.eq(self.i.a.s == self.i.b.s),
70 mge.eq(self.i.a.m >= self.i.b.m),
71 am0.eq(Cat(self.i.a.m, 0)),
72 bm0.eq(Cat(self.i.b.m, 0))
73 ]
74 # same-sign (both negative or both positive) add mantissas
75 with m.If(~self.i.out_do_z):
76 m.d.comb += self.o.z.e.eq(self.i.a.e)
77 with m.If(seq):
78 m.d.comb += [
79 self.o.tot.eq(am0 + bm0),
80 self.o.z.s.eq(self.i.a.s)
81 ]
82 # a mantissa greater than b, use a
83 with m.Elif(mge):
84 m.d.comb += [
85 self.o.tot.eq(am0 - bm0),
86 self.o.z.s.eq(self.i.a.s)
87 ]
88 # b mantissa greater than a, use b
89 with m.Else():
90 m.d.comb += [
91 self.o.tot.eq(bm0 - am0),
92 self.o.z.s.eq(self.i.b.s)
93 ]
94
95 m.d.comb += self.o.oz.eq(self.i.oz)
96 m.d.comb += self.o.out_do_z.eq(self.i.out_do_z)
97 m.d.comb += self.o.mid.eq(self.i.mid)
98 return m
99
100
101 class FPAddStage0(FPState):
102 """ First stage of add. covers same-sign (add) and subtract
103 special-casing when mantissas are greater or equal, to
104 give greatest accuracy.
105 """
106
107 def __init__(self, width, id_wid):
108 FPState.__init__(self, "add_0")
109 self.mod = FPAddStage0Mod(width)
110 self.o = self.mod.ospec()
111
112 def setup(self, m, i):
113 """ links module to inputs and outputs
114 """
115 self.mod.setup(m, i)
116
117 # NOTE: these could be done as combinatorial (merge add0+add1)
118 m.d.sync += self.o.eq(self.mod.o)
119
120 def action(self, m):
121 m.next = "add_1"