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