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