1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
6 from nmigen
.cli
import main
10 def __init__(self
, width
):
13 self
.in_a
= Signal(width
)
14 self
.in_a_stb
= Signal()
15 self
.in_a_ack
= Signal()
17 self
.in_b
= Signal(width
)
18 self
.in_b_stb
= Signal()
19 self
.in_b_ack
= Signal()
21 self
.out_z
= Signal(width
)
22 self
.out_z_stb
= Signal()
23 self
.out_z_ack
= Signal()
25 s_out_z_stb
= Signal()
26 s_out_z
= Signal(width
)
30 def get_fragment(self
, platform
):
34 a
= Signal(self
.width
)
35 b
= Signal(self
.width
)
36 z
= Signal(self
.width
)
60 with m
.State("get_a"):
61 with m
.If((self
.in_a_ack
) & (self
.in_a_stb
)):
68 m
.d
.sync
+= self
.in_a_ack
.eq(1)
70 with m
.State("get_b"):
71 with m
.If((self
.in_b_ack
) & (self
.in_b_stb
)):
78 m
.d
.sync
+= self
.in_b_ack
.eq(1)
80 with m
.State("unpack"):
81 m
.next
= "special_cases"
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),
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))):
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...
105 always @(posedge clk)
113 if (s_in_a_ack && in_a_stb) begin
123 if (s_in_b_ack && in_b_stb) 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;
138 state <= special_cases;
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
150 //if a is inf return inf
151 end else if (a_e == 128) begin
155 //if a is inf and signs don't match return nan
156 if ((b_e == 128) && (a_s != b_s)) begin
163 //if b is inf return inf
164 end else if (b_e == 128) begin
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
172 z[30:23] <= b_e[7:0] + 127;
173 z[22:0] <= b_m[26:3];
175 //if a is zero return b
176 end else if (($signed(a_e) == -127) && (a_m == 0)) begin
178 z[30:23] <= b_e[7:0] + 127;
179 z[22:0] <= b_m[26:3];
181 //if b is zero return a
182 end else if (($signed(b_e) == -127) && (b_m == 0)) begin
184 z[30:23] <= a_e[7:0] + 127;
185 z[22:0] <= a_m[26:3];
188 //Denormalised Number
189 if ($signed(a_e) == -127) begin
194 //Denormalised Number
195 if ($signed(b_e) == -127) begin
206 if ($signed(a_e) > $signed(b_e)) begin
209 b_m[0] <= b_m[0] | b_m[1];
210 end else if ($signed(a_e) < $signed(b_e)) begin
213 a_m[0] <= a_m[0] | a_m[1];
222 if (a_s == b_s) begin
226 if (a_m >= b_m) begin
243 sticky <= tot[1] | tot[0];
251 state <= normalise_1;
256 if (z_m[23] == 0 && $signed(z_e) > -126) begin
263 state <= normalise_2;
269 if ($signed(z_e) < -126) begin
274 sticky <= sticky | round_bit;
282 if (guard && (round_bit | sticky | z_m[0])) begin
284 if (z_m == 24'hffffff) begin
293 z[22 : 0] <= z_m[22:0];
294 z[30 : 23] <= z_e[7:0] + 127;
296 if ($signed(z_e) == -126 && z_m[23] == 0) begin
299 if ($signed(z_e) == -126 && z_m[23:0] == 24'h0) begin
300 z[31] <= 1'b0; // FIX SIGN BUG: -a + a = +0.
302 //if overflow occurs, return inf
303 if ($signed(z_e) > 127) begin
315 if (s_out_z_stb && out_z_ack) begin
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;
339 if __name__
== "__main__":
340 alu
= FPADD(width
=32)
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
,