add regressions and corner cases
[ieee754fpu.git] / src / ieee754 / fpcommon / test / unit_test_single.py
1 from random import randint
2 from random import seed
3
4 import sys
5 from sfpy import Float32
6
7 def get_mantissa(x):
8 return 0x7fffff & x
9
10 def get_exponent(x):
11 return ((x & 0x7f800000) >> 23) - 127
12
13 def set_exponent(x, e):
14 return (x & ~0x7f800000) | ((e+127) << 23)
15
16 def get_sign(x):
17 return ((x & 0x80000000) >> 31)
18
19 def is_nan(x):
20 return get_exponent(x) == 128 and get_mantissa(x) != 0
21
22 def is_inf(x):
23 return get_exponent(x) == 128 and get_mantissa(x) == 0
24
25 def is_pos_inf(x):
26 return is_inf(x) and not get_sign(x)
27
28 def is_neg_inf(x):
29 return is_inf(x) and get_sign(x)
30
31 def match(x, y):
32 return (
33 (is_pos_inf(x) and is_pos_inf(y)) or
34 (is_neg_inf(x) and is_neg_inf(y)) or
35 (is_nan(x) and is_nan(y)) or
36 (x == y)
37 )
38
39 def create(s, e, m):
40 return set_exponent((s<<31) | m, e)
41
42 def inf(s):
43 return create(s, 128, 0)
44
45 def nan(s):
46 return create(s, 128, 1<<22)
47
48 def zero(s):
49 return s<<31
50
51
52 def get_rs_case(dut, a, b, mid):
53 in_a, in_b = dut.rs[0]
54 out_z = dut.res[0]
55 yield dut.ids.in_mid.eq(mid)
56 yield in_a.v.eq(a)
57 yield in_a.valid_i.eq(1)
58 yield
59 yield
60 yield
61 yield
62 a_ack = (yield in_a.ready_o)
63 assert a_ack == 0
64
65 yield in_a.valid_i.eq(0)
66
67 yield in_b.v.eq(b)
68 yield in_b.valid_i.eq(1)
69 yield
70 yield
71 b_ack = (yield in_b.ready_o)
72 assert b_ack == 0
73
74 yield in_b.valid_i.eq(0)
75
76 yield out_z.ready_i.eq(1)
77
78 while True:
79 out_z_stb = (yield out_z.valid_o)
80 if not out_z_stb:
81 yield
82 continue
83 vout_z = yield out_z.v
84 #out_mid = yield dut.ids.out_mid
85 yield out_z.ready_i.eq(0)
86 yield
87 break
88
89 return vout_z, mid
90
91 def check_rs_case(dut, a, b, z, mid=None):
92 if mid is None:
93 mid = randint(0, 6)
94 mid = 0
95 out_z, out_mid = yield from get_rs_case(dut, a, b, mid)
96 assert out_z == z, "Output z 0x%x not equal to expected 0x%x" % (out_z, z)
97 assert out_mid == mid, "Output mid 0x%x != expected 0x%x" % (out_mid, mid)
98
99
100 def get_case(dut, a, b, mid):
101 #yield dut.in_mid.eq(mid)
102 yield dut.in_a.v.eq(a)
103 yield dut.in_a.valid_i_test.eq(1)
104 yield
105 yield
106 yield
107 yield
108 a_ack = (yield dut.in_a.ready_o)
109 assert a_ack == 0
110
111 yield dut.in_a.valid_i.eq(0)
112
113 yield dut.in_b.v.eq(b)
114 yield dut.in_b.valid_i.eq(1)
115 yield
116 yield
117 b_ack = (yield dut.in_b.ready_o)
118 assert b_ack == 0
119
120 yield dut.in_b.valid_i.eq(0)
121
122 yield dut.out_z.ready_i.eq(1)
123
124 while True:
125 out_z_stb = (yield dut.out_z.valid_o)
126 if not out_z_stb:
127 yield
128 continue
129 out_z = yield dut.out_z.v
130 #out_mid = yield dut.out_mid
131 yield dut.out_z.ready_i.eq(0)
132 yield
133 break
134
135 return out_z, mid # TODO: mid
136
137 def check_case(dut, a, b, z, mid=None):
138 if mid is None:
139 mid = randint(0, 6)
140 mid = 0
141 out_z, out_mid = yield from get_case(dut, a, b, mid)
142 assert out_z == z, "Output z 0x%x not equal to expected 0x%x" % (out_z, z)
143 assert out_mid == mid, "Output mid 0x%x != expected 0x%x" % (out_mid, mid)
144
145
146 def run_fpunit(dut, stimulus_a, stimulus_b, op, get_case_fn):
147
148 expected_responses = []
149 actual_responses = []
150 for a, b in zip(stimulus_a, stimulus_b):
151 mid = randint(0, 6)
152 mid = 0
153 af = Float32.from_bits(a)
154 bf = Float32.from_bits(b)
155 z = op(af, bf)
156 expected_responses.append((z.get_bits(), mid))
157 actual = yield from get_case_fn(dut, a, b, mid)
158 actual_responses.append(actual)
159
160 if len(actual_responses) < len(expected_responses):
161 print ("Fail ... not enough results")
162 exit(0)
163
164 for expected, actual, a, b in zip(expected_responses, actual_responses,
165 stimulus_a, stimulus_b):
166 passed = match(expected[0], actual[0])
167 if expected[1] != actual[1]: # check mid
168 print ("MID failed", expected[1], actual[1])
169 sys.exit(0)
170
171 if not passed:
172
173 expected = expected[0]
174 actual = actual[0]
175 print ("Fail ... expected:", hex(expected), "actual:", hex(actual))
176
177 print (hex(a))
178 print ("a mantissa:", a & 0x7fffff)
179 print ("a exponent:", ((a & 0x7f800000) >> 23) - 127)
180 print ("a sign:", ((a & 0x80000000) >> 31))
181
182 print (hex(b))
183 print ("b mantissa:", b & 0x7fffff)
184 print ("b exponent:", ((b & 0x7f800000) >> 23) - 127)
185 print ("b sign:", ((b & 0x80000000) >> 31))
186
187 print (hex(expected))
188 print ("expected mantissa:", expected & 0x7fffff)
189 print ("expected exponent:", ((expected & 0x7f800000) >> 23) - 127)
190 print ("expected sign:", ((expected & 0x80000000) >> 31))
191
192 print (hex(actual))
193 print ("actual mantissa:", actual & 0x7fffff)
194 print ("actual exponent:", ((actual & 0x7f800000) >> 23) - 127)
195 print ("actual sign:", ((actual & 0x80000000) >> 31))
196
197 sys.exit(0)
198
199 corner_cases = [0x80000000, 0x00000000, 0x7f800000, 0xff800000,
200 0x7fc00000, 0xffc00000]
201
202 def run_corner_cases(dut, count, op, get_case_fn):
203 #corner cases
204 from itertools import permutations
205 stimulus_a = [i[0] for i in permutations(corner_cases, 2)]
206 stimulus_b = [i[1] for i in permutations(corner_cases, 2)]
207 yield from run_fpunit(dut, stimulus_a, stimulus_b, op, get_case_fn)
208 count += len(stimulus_a)
209 print (count, "vectors passed")
210
211 def run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn):
212 yield from run_fpunit(dut, stimulus_a, stimulus_b, op, get_case_fn)
213 yield from run_fpunit(dut, stimulus_b, stimulus_a, op, get_case_fn)
214
215 def run_cases(dut, count, op, fixed_num, maxcount, get_case_fn):
216 if isinstance(fixed_num, int):
217 stimulus_a = [fixed_num for i in range(maxcount)]
218 report = hex(fixed_num)
219 else:
220 stimulus_a = fixed_num
221 report = "random"
222
223 stimulus_b = [randint(0, 1<<32) for i in range(maxcount)]
224 yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
225 count += len(stimulus_a)
226 print (count, "vectors passed 2^32", report)
227
228 # non-canonical NaNs.
229 stimulus_b = [set_exponent(randint(0, 1<<32), 128) \
230 for i in range(maxcount)]
231 yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
232 count += len(stimulus_a)
233 print (count, "vectors passed Non-Canonical NaN", report)
234
235 # -127
236 stimulus_b = [set_exponent(randint(0, 1<<32), -127) \
237 for i in range(maxcount)]
238 yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
239 count += len(stimulus_a)
240 print (count, "vectors passed exp=-127", report)
241
242 # nearly zero
243 stimulus_b = [set_exponent(randint(0, 1<<32), -126) \
244 for i in range(maxcount)]
245 yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
246 count += len(stimulus_a)
247 print (count, "vectors passed exp=-126", report)
248
249 # nearly inf
250 stimulus_b = [set_exponent(randint(0, 1<<32), 127) \
251 for i in range(maxcount)]
252 yield from run_fpunit_2(dut, stimulus_a, stimulus_b, op, get_case_fn)
253 count += len(stimulus_a)
254 print (count, "vectors passed exp=127", report)
255
256 return count
257
258 def run_edge_cases(dut, count, op, get_case_fn, maxcount=10, num_loops=1000):
259 #edge cases
260 for testme in corner_cases:
261 count = yield from run_cases(dut, count, op, testme,
262 maxcount, get_case_fn)
263
264 for i in range(num_loops):
265 stimulus_a = [randint(0, 1<<32) for i in range(maxcount)]
266 count = yield from run_cases(dut, count, op, stimulus_a, 10,
267 get_case_fn)
268 return count
269