special cases, sign of zero and inf matters: a.s ^ b.s
[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 = (self.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 m.next = "normalise_1"
107 m.d.sync += [
108 z.m.eq(product[26:50]),
109 of.guard.eq(product[25]),
110 of.round_bit.eq(product[24]),
111 of.sticky.eq(product[0:23] != 0)
112 ]
113
114 # ******
115 # First stage of normalisation.
116 with m.State("normalise_1"):
117 self.normalise_1(m, z, of, "normalise_2")
118
119 # ******
120 # Second stage of normalisation.
121
122 with m.State("normalise_2"):
123 self.normalise_2(m, z, of, "round")
124
125 # ******
126 # rounding stage
127
128 with m.State("round"):
129 self.roundz(m, z, of, "corrections")
130
131 # ******
132 # correction stage
133
134 with m.State("corrections"):
135 self.corrections(m, z, "pack")
136
137 # ******
138 # pack stage
139 with m.State("pack"):
140 self.pack(m, z, "put_z")
141
142 # ******
143 # put_z stage
144
145 with m.State("put_z"):
146 self.put_z(m, z, self.out_z, "get_a")
147
148 return m
149
150 """
151 special_cases:
152 begin
153 //if a is NaN or b is NaN return NaN
154 if ((a_e == 128 && a_m != 0) || (b_e == 128 && b_m != 0)) begin
155 z[31] <= 1;
156 z[30:23] <= 255;
157 z[22] <= 1;
158 z[21:0] <= 0;
159 state <= put_z;
160 //if a is inf return inf
161 end else if (a_e == 128) begin
162 z[31] <= a_s ^ b_s;
163 z[30:23] <= 255;
164 z[22:0] <= 0;
165 //if b is zero return NaN
166 if (($signed(b_e) == -127) && (b_m == 0)) begin
167 z[31] <= 1;
168 z[30:23] <= 255;
169 z[22] <= 1;
170 z[21:0] <= 0;
171 end
172 state <= put_z;
173 //if b is inf return inf
174 end else if (b_e == 128) begin
175 z[31] <= a_s ^ b_s;
176 z[30:23] <= 255;
177 z[22:0] <= 0;
178 //if a is zero return NaN
179 if (($signed(a_e) == -127) && (a_m == 0)) begin
180 z[31] <= 1;
181 z[30:23] <= 255;
182 z[22] <= 1;
183 z[21:0] <= 0;
184 end
185 state <= put_z;
186 //if a is zero return zero
187 end else if (($signed(a_e) == -127) && (a_m == 0)) begin
188 z[31] <= a_s ^ b_s;
189 z[30:23] <= 0;
190 z[22:0] <= 0;
191 state <= put_z;
192 //if b is zero return zero
193 end else if (($signed(b_e) == -127) && (b_m == 0)) begin
194 z[31] <= a_s ^ b_s;
195 z[30:23] <= 0;
196 z[22:0] <= 0;
197 state <= put_z;
198 //^ done up to here
199 end else begin
200 //Denormalised Number
201 if ($signed(a_e) == -127) begin
202 a_e <= -126;
203 end else begin
204 a_m[23] <= 1;
205 end
206 //Denormalised Number
207 if ($signed(b_e) == -127) begin
208 b_e <= -126;
209 end else begin
210 b_m[23] <= 1;
211 end
212 state <= normalise_a;
213 end
214 end
215
216 normalise_a:
217 begin
218 if (a_m[23]) begin
219 state <= normalise_b;
220 end else begin
221 a_m <= a_m << 1;
222 a_e <= a_e - 1;
223 end
224 end
225
226 normalise_b:
227 begin
228 if (b_m[23]) begin
229 state <= multiply_0;
230 end else begin
231 b_m <= b_m << 1;
232 b_e <= b_e - 1;
233 end
234 end
235
236 multiply_0:
237 begin
238 z_s <= a_s ^ b_s;
239 z_e <= a_e + b_e + 1;
240 product <= a_m * b_m * 4;
241 state <= multiply_1;
242 end
243
244 multiply_1:
245 begin
246 z_m <= product[49:26];
247 guard <= product[25];
248 round_bit <= product[24];
249 sticky <= (product[23:0] != 0);
250 state <= normalise_1;
251 end
252
253 normalise_1:
254 begin
255 if (z_m[23] == 0) begin
256 z_e <= z_e - 1;
257 z_m <= z_m << 1;
258 z_m[0] <= guard;
259 guard <= round_bit;
260 round_bit <= 0;
261 end else begin
262 state <= normalise_2;
263 end
264 end
265
266 normalise_2:
267 begin
268 if ($signed(z_e) < -126) begin
269 z_e <= z_e + 1;
270 z_m <= z_m >> 1;
271 guard <= z_m[0];
272 round_bit <= guard;
273 sticky <= sticky | round_bit;
274 end else begin
275 state <= round;
276 end
277 end
278
279 round:
280 begin
281 if (guard && (round_bit | sticky | z_m[0])) begin
282 z_m <= z_m + 1;
283 if (z_m == 24'hffffff) begin
284 z_e <=z_e + 1;
285 end
286 end
287 state <= pack;
288 end
289
290 pack:
291 begin
292 z[22 : 0] <= z_m[22:0];
293 z[30 : 23] <= z_e[7:0] + 127;
294 z[31] <= z_s;
295 if ($signed(z_e) == -126 && z_m[23] == 0) begin
296 z[30 : 23] <= 0;
297 end
298 //if overflow occur
299 s, return inf
300 if ($signed(z_e) > 127) begin
301 z[22 : 0] <= 0;
302 z[30 : 23] <= 255;
303 z[31] <= z_s;
304 end
305 state <= put_z;
306 end
307
308 put_z:
309 begin
310 s_output_z_stb <= 1;
311 s_output_z <= z;
312 if (s_output_z_stb && output_z_ack) begin
313 s_output_z_stb <= 0;
314 state <= get_a;
315 end
316 end
317
318 """
319
320 if __name__ == "__main__":
321 alu = FPMUL(width=32)
322 main(alu, ports=alu.in_a.ports() + alu.in_b.ports() + alu.out_z.ports())