whitespace (indent)
[ieee754fpu.git] / src / add / nmigen_add_experiment.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
6 from nmigen.cli import main
7
8
9 class FPADD:
10 def __init__(self, width):
11 self.width = width
12
13 self.in_a = Signal(width)
14 self.in_a_stb = Signal()
15 self.in_a_ack = Signal()
16
17 self.in_b = Signal(width)
18 self.in_b_stb = Signal()
19 self.in_b_ack = Signal()
20
21 self.out_z = Signal(width)
22 self.out_z_stb = Signal()
23 self.out_z_ack = Signal()
24
25 s_out_z_stb = Signal()
26 s_out_z = Signal(width)
27 s_in_a_ack = Signal()
28 s_in_b_ack = Signal()
29
30 def get_fragment(self, platform):
31 m = Module()
32
33 # Latches
34 a = Signal(self.width)
35 b = Signal(self.width)
36 z = Signal(self.width)
37
38 # Mantissa
39 a_m = Signal(27)
40 b_m = Signal(27)
41 z_m = Signal(23)
42
43 # Exponent
44 a_e = Signal(10)
45 b_e = Signal(10)
46 z_e = Signal(10)
47
48 # Sign
49 a_s = Signal()
50 b_s = Signal()
51 z_s = Signal()
52
53 guard = Signal()
54 round_bit = Signal()
55 sticky = Signal()
56
57 tot = Signal(28)
58
59 with m.FSM() as fsm:
60 with m.State("get_a"):
61 with m.If((self.in_a_ack) & (self.in_a_stb)):
62 m.next = "get_b"
63 m.d.sync += [
64 a.eq(self.in_a),
65 self.in_a_ack.eq(0)
66 ]
67 with m.Else():
68 m.d.sync += self.in_a_ack.eq(1)
69
70 with m.State("get_b"):
71 with m.If((self.in_b_ack) & (self.in_b_stb)):
72 m.next = "get_a"
73 m.d.sync += [
74 b.eq(self.in_b),
75 self.in_b_ack.eq(0)
76 ]
77 with m.Else():
78 m.d.sync += self.in_b_ack.eq(1)
79
80 with m.State("unpack"):
81 m.next = "special_cases"
82 m.d.sync += [
83 a_m.eq(Cat(0, 0, 0, a[0:23])),
84 b_m.eq(Cat(0, 0, 0, b[0:23])),
85 a_e.eq(Cat(a[23:31]) - 127),
86 b_e.eq(Cat(b[23:31]) - 127),
87 a_s.eq(Cat(a[31])),
88 b_s.eq(Cat(b[31]))
89 ]
90
91 with m.State("special_cases"):
92 # if a is NaN or b is NaN return NaN
93 with m.If(((a_e == 128) & (a_m != 0)) | \
94 ((b_e == 128) & (b_m != 0))):
95 m.next = "put_z"
96 m.d.sync += [
97 z[31].eq(1), # sign: 1
98 z[23:31].eq(255), # exp: 0b11111...
99 z[22].eq(1), # mantissa top bit: 1
100 z[0:22].eq(0) # mantissa rest: 0b0000...
101 ]
102 return m
103
104 """
105 always @(posedge clk)
106 begin
107
108 case(state)
109
110 get_a:
111 begin
112 s_in_a_ack <= 1;
113 if (s_in_a_ack && in_a_stb) begin
114 a <= in_a;
115 s_in_a_ack <= 0;
116 state <= get_b;
117 end
118 end
119
120 get_b:
121 begin
122 s_in_b_ack <= 1;
123 if (s_in_b_ack && in_b_stb) begin
124 b <= in_b;
125 s_in_b_ack <= 0;
126 state <= unpack;
127 end
128 end
129
130 unpack:
131 begin
132 a_m <= {a[22 : 0], 3'd0};
133 b_m <= {b[22 : 0], 3'd0};
134 a_e <= a[30 : 23] - 127;
135 b_e <= b[30 : 23] - 127;
136 a_s <= a[31];
137 b_s <= b[31];
138 state <= special_cases;
139 end
140
141 special_cases:
142 begin
143 //if a is NaN or b is NaN return NaN
144 if ((a_e == 128 && a_m != 0) || (b_e == 128 && b_m != 0)) begin
145 z[31] <= 1;
146 z[30:23] <= 255;
147 z[22] <= 1;
148 z[21:0] <= 0;
149 state <= put_z;
150 //if a is inf return inf
151 end else if (a_e == 128) begin
152 z[31] <= a_s;
153 z[30:23] <= 255;
154 z[22:0] <= 0;
155 //if a is inf and signs don't match return nan
156 if ((b_e == 128) && (a_s != b_s)) begin
157 z[31] <= b_s;
158 z[30:23] <= 255;
159 z[22] <= 1;
160 z[21:0] <= 0;
161 end
162 state <= put_z;
163 //if b is inf return inf
164 end else if (b_e == 128) begin
165 z[31] <= b_s;
166 z[30:23] <= 255;
167 z[22:0] <= 0;
168 state <= put_z;
169 //if a is zero return b
170 end else if ((($signed(a_e) == -127) && (a_m == 0)) && (($signed(b_e) == -127) && (b_m == 0))) begin
171 z[31] <= a_s & b_s;
172 z[30:23] <= b_e[7:0] + 127;
173 z[22:0] <= b_m[26:3];
174 state <= put_z;
175 //if a is zero return b
176 end else if (($signed(a_e) == -127) && (a_m == 0)) begin
177 z[31] <= b_s;
178 z[30:23] <= b_e[7:0] + 127;
179 z[22:0] <= b_m[26:3];
180 state <= put_z;
181 //if b is zero return a
182 end else if (($signed(b_e) == -127) && (b_m == 0)) begin
183 z[31] <= a_s;
184 z[30:23] <= a_e[7:0] + 127;
185 z[22:0] <= a_m[26:3];
186 state <= put_z;
187 end else begin
188 //Denormalised Number
189 if ($signed(a_e) == -127) begin
190 a_e <= -126;
191 end else begin
192 a_m[26] <= 1;
193 end
194 //Denormalised Number
195 if ($signed(b_e) == -127) begin
196 b_e <= -126;
197 end else begin
198 b_m[26] <= 1;
199 end
200 state <= align;
201 end
202 end
203
204 align:
205 begin
206 if ($signed(a_e) > $signed(b_e)) begin
207 b_e <= b_e + 1;
208 b_m <= b_m >> 1;
209 b_m[0] <= b_m[0] | b_m[1];
210 end else if ($signed(a_e) < $signed(b_e)) begin
211 a_e <= a_e + 1;
212 a_m <= a_m >> 1;
213 a_m[0] <= a_m[0] | a_m[1];
214 end else begin
215 state <= add_0;
216 end
217 end
218
219 add_0:
220 begin
221 z_e <= a_e;
222 if (a_s == b_s) begin
223 tot <= a_m + b_m;
224 z_s <= a_s;
225 end else begin
226 if (a_m >= b_m) begin
227 tot <= a_m - b_m;
228 z_s <= a_s;
229 end else begin
230 tot <= b_m - a_m;
231 z_s <= b_s;
232 end
233 end
234 state <= add_1;
235 end
236
237 add_1:
238 begin
239 if (tot[27]) begin
240 z_m <= tot[27:4];
241 guard <= tot[3];
242 round_bit <= tot[2];
243 sticky <= tot[1] | tot[0];
244 z_e <= z_e + 1;
245 end else begin
246 z_m <= tot[26:3];
247 guard <= tot[2];
248 round_bit <= tot[1];
249 sticky <= tot[0];
250 end
251 state <= normalise_1;
252 end
253
254 normalise_1:
255 begin
256 if (z_m[23] == 0 && $signed(z_e) > -126) begin
257 z_e <= z_e - 1;
258 z_m <= z_m << 1;
259 z_m[0] <= guard;
260 guard <= round_bit;
261 round_bit <= 0;
262 end else begin
263 state <= normalise_2;
264 end
265 end
266
267 normalise_2:
268 begin
269 if ($signed(z_e) < -126) begin
270 z_e <= z_e + 1;
271 z_m <= z_m >> 1;
272 guard <= z_m[0];
273 round_bit <= guard;
274 sticky <= sticky | round_bit;
275 end else begin
276 state <= round;
277 end
278 end
279
280 round:
281 begin
282 if (guard && (round_bit | sticky | z_m[0])) begin
283 z_m <= z_m + 1;
284 if (z_m == 24'hffffff) begin
285 z_e <=z_e + 1;
286 end
287 end
288 state <= pack;
289 end
290
291 pack:
292 begin
293 z[22 : 0] <= z_m[22:0];
294 z[30 : 23] <= z_e[7:0] + 127;
295 z[31] <= z_s;
296 if ($signed(z_e) == -126 && z_m[23] == 0) begin
297 z[30 : 23] <= 0;
298 end
299 if ($signed(z_e) == -126 && z_m[23:0] == 24'h0) begin
300 z[31] <= 1'b0; // FIX SIGN BUG: -a + a = +0.
301 end
302 //if overflow occurs, return inf
303 if ($signed(z_e) > 127) begin
304 z[22 : 0] <= 0;
305 z[30 : 23] <= 255;
306 z[31] <= z_s;
307 end
308 state <= put_z;
309 end
310
311 put_z:
312 begin
313 s_out_z_stb <= 1;
314 s_out_z <= z;
315 if (s_out_z_stb && out_z_ack) begin
316 s_out_z_stb <= 0;
317 state <= get_a;
318 end
319 end
320
321 endcase
322
323 if (rst == 1) begin
324 state <= get_a;
325 s_in_a_ack <= 0;
326 s_in_b_ack <= 0;
327 s_out_z_stb <= 0;
328 end
329
330 end
331 assign in_a_ack = s_in_a_ack;
332 assign in_b_ack = s_in_b_ack;
333 assign out_z_stb = s_out_z_stb;
334 assign out_z = s_out_z;
335
336 endmodule
337 """
338
339 if __name__ == "__main__":
340 alu = FPADD(width=32)
341 main(alu, ports=[
342 alu.in_a, alu.in_a_stb, alu.in_a_ack,
343 alu.in_b, alu.in_b_stb, alu.in_b_ack,
344 alu.out_z, alu.out_z_stb, alu.out_z_ack,
345 ])