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