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