more code-shuffling into subdirs
[ieee754fpu.git] / src / ieee754 / fpmul / fmul.py
1 from nmigen import Module, Signal, Cat, Mux, Array, Const
2 from nmigen.cli import main, verilog
3
4 from fpbase import FPNumIn, FPNumOut, FPOp, Overflow, FPBase, FPState
5 from fpcommon.getop import FPGetOp
6 from nmutil.singlepipe import eq
7
8
9 class FPMUL(FPBase):
10
11 def __init__(self, width):
12 FPBase.__init__(self)
13 self.width = width
14
15 self.in_a = FPOp(width)
16 self.in_b = FPOp(width)
17 self.out_z = FPOp(width)
18
19 self.states = []
20
21 def add_state(self, state):
22 self.states.append(state)
23 return state
24
25 def elaborate(self, platform=None):
26 """ creates the HDL code-fragment for FPMUL
27 """
28 m = Module()
29
30 # Latches
31 a = FPNumIn(None, self.width, False)
32 b = FPNumIn(None, self.width, False)
33 z = FPNumOut(self.width, False)
34
35 mw = (z.m_width)*2 - 1 + 3 # sticky/round/guard bits + (2*mant) - 1
36 product = Signal(mw)
37
38 of = Overflow()
39 m.submodules.of = of
40 m.submodules.a = a
41 m.submodules.b = b
42 m.submodules.z = z
43
44 m.d.comb += a.v.eq(self.in_a.v)
45 m.d.comb += b.v.eq(self.in_b.v)
46
47 with m.FSM() as fsm:
48
49 # ******
50 # gets operand a
51
52 with m.State("get_a"):
53 res = self.get_op(m, self.in_a, a, "get_b")
54 m.d.sync += eq([a, self.in_a.ack], res)
55
56 # ******
57 # gets operand b
58
59 with m.State("get_b"):
60 res = self.get_op(m, self.in_b, b, "special_cases")
61 m.d.sync += eq([b, self.in_b.ack], res)
62
63 # ******
64 # special cases
65
66 with m.State("special_cases"):
67 #if a or b is NaN return NaN
68 with m.If(a.is_nan | b.is_nan):
69 m.next = "put_z"
70 m.d.sync += z.nan(1)
71 #if a is inf return inf
72 with m.Elif(a.is_inf):
73 m.next = "put_z"
74 m.d.sync += z.inf(a.s ^ b.s)
75 #if b is zero return NaN
76 with m.If(b.is_zero):
77 m.d.sync += z.nan(1)
78 #if b is inf return inf
79 with m.Elif(b.is_inf):
80 m.next = "put_z"
81 m.d.sync += z.inf(a.s ^ b.s)
82 #if a is zero return NaN
83 with m.If(a.is_zero):
84 m.next = "put_z"
85 m.d.sync += z.nan(1)
86 #if a is zero return zero
87 with m.Elif(a.is_zero):
88 m.next = "put_z"
89 m.d.sync += z.zero(a.s ^ b.s)
90 #if b is zero return zero
91 with m.Elif(b.is_zero):
92 m.next = "put_z"
93 m.d.sync += z.zero(a.s ^ b.s)
94 # Denormalised Number checks
95 with m.Else():
96 m.next = "normalise_a"
97 self.denormalise(m, a)
98 self.denormalise(m, b)
99
100 # ******
101 # normalise_a
102
103 with m.State("normalise_a"):
104 self.op_normalise(m, a, "normalise_b")
105
106 # ******
107 # normalise_b
108
109 with m.State("normalise_b"):
110 self.op_normalise(m, b, "multiply_0")
111
112 #multiply_0
113 with m.State("multiply_0"):
114 m.next = "multiply_1"
115 m.d.sync += [
116 z.s.eq(a.s ^ b.s),
117 z.e.eq(a.e + b.e + 1),
118 product.eq(a.m * b.m * 4)
119 ]
120
121 #multiply_1
122 with m.State("multiply_1"):
123 mw = z.m_width
124 m.next = "normalise_1"
125 m.d.sync += [
126 z.m.eq(product[mw+2:]),
127 of.guard.eq(product[mw+1]),
128 of.round_bit.eq(product[mw]),
129 of.sticky.eq(product[0:mw] != 0)
130 ]
131
132 # ******
133 # First stage of normalisation.
134 with m.State("normalise_1"):
135 self.normalise_1(m, z, of, "normalise_2")
136
137 # ******
138 # Second stage of normalisation.
139
140 with m.State("normalise_2"):
141 self.normalise_2(m, z, of, "round")
142
143 # ******
144 # rounding stage
145
146 with m.State("round"):
147 self.roundz(m, z, of.roundz)
148 m.next = "corrections"
149
150 # ******
151 # correction stage
152
153 with m.State("corrections"):
154 self.corrections(m, z, "pack")
155
156 # ******
157 # pack stage
158 with m.State("pack"):
159 self.pack(m, z, "put_z")
160
161 # ******
162 # put_z stage
163
164 with m.State("put_z"):
165 self.put_z(m, z, self.out_z, "get_a")
166
167 return m
168
169
170 if __name__ == "__main__":
171 alu = FPMUL(width=32)
172 main(alu, ports=alu.in_a.ports() + alu.in_b.ports() + alu.out_z.ports())