Skip to content

Commit e1ead21

Browse files
committed
Improve testbench and add python script to generate test vector
1 parent 518f07b commit e1ead21

File tree

4 files changed

+197
-14
lines changed

4 files changed

+197
-14
lines changed

floatsip/sim/doCompileFPVerifier.do

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
set SIMLIBPATH {/fpgasw/altera/12.1sp1/quartus/eda/sim_lib/}
1+
set SIMLIBPATH {D:/intelFPGA_lite/18.0/quartus/eda/sim_lib/}
22
puts $SIMLIBPATH
33
vlog $SIMLIBPATH/220model.v
44
vlog $SIMLIBPATH/altera_mf.v

floatsip/sim/float_util.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
2+
import math
3+
import random
4+
5+
FloatingPoint_Specification = {
6+
32 : ( 8, 23) ,
7+
64 : (11, 52) ,
8+
16 : ( 5, 10)
9+
}
10+
11+
def is_inf(dbl, exp_width):
12+
bias = (1<<(exp_width - 1)) - 1
13+
max_e = (1<<exp_width) - 1 - 1 - bias
14+
if exp_width == 11:
15+
return math.isinf(dbl)
16+
else:
17+
return (dbl >= math.ldexp(1.0, max_e + 1) or dbl < math.ldexp(-1.0, max_e + 1))
18+
19+
def is_subnormal(dbl, exp_width):
20+
bias = (1<<(exp_width - 1)) - 1
21+
min_e = 1 - bias
22+
return ((dbl < math.ldexp(1.0, min_e) and dbl > math.ldexp(-1.0, min_e)) and dbl != 0.0)
23+
24+
25+
def gen_rand_float(size):
26+
e_width, m_width = FloatingPoint_Specification[size]
27+
m = random.randint(0, 2**(m_width + 1) - 1)
28+
mant = m/2.0**m_width
29+
bias = (1<<(e_width - 1)) - 1
30+
max_e = ((1 << e_width) - 1) - 1 - bias
31+
min_e = (1 - bias)
32+
exp = random.randint(min_e, max_e)
33+
return math.ldexp(mant, exp)
34+
35+
def round_to_nearest_even(dbl):
36+
upper = math.ceil(dbl)
37+
lower = math.floor(dbl)
38+
error = dbl - lower
39+
ret = 0
40+
if error == 0.5:
41+
if (upper % 2)==0:
42+
ret = upper
43+
else:
44+
ret =lower
45+
elif error < 0.5:
46+
ret = lower
47+
else:
48+
ret = upper
49+
return int(ret)
50+
51+
def hex_rep(dbl, exp_width = 8, mant_width = 23):
52+
"""
53+
This function returns hex representation of dbl value with a custom exp_width and mant_width
54+
First find out the BIAS and the representation of the dbl
55+
dlb = m * 2^e ( m is [-1.0, 1.0])
56+
Then we handle infinity, handle subnormal number and special case for zero
57+
"""
58+
59+
bias = (1<<(exp_width - 1)) - 1
60+
m, e = math.frexp(dbl)
61+
62+
try:
63+
#Infinity number
64+
if is_inf(dbl, exp_width):
65+
mant = 0
66+
exp = (1<<exp_width) - 1
67+
68+
#subnormal numbers
69+
elif is_subnormal(dbl, exp_width):
70+
"""
71+
subnormal number a = s * 0.m * 2^min_e (min_e = 1 - bias)
72+
the frexp() returns normalized m and e with 0.5 <= m <= 1.0 and e can be smaller than 1 - bias
73+
to represent a = m x 2^e in subnormal format = 0.frac x 2^min_e
74+
we have to unnormalize the mantissa
75+
frac = m / (2^(min_e - e))
76+
then multiply by number of bits of mantissa = 2^mant_width
77+
--> frac = m * 2^(mant_width - (min_e - e))
78+
"""
79+
exp = 0
80+
k = (1-bias) - e
81+
if m < 0:
82+
m = 0 - m
83+
if mant_width >= k:
84+
mant = int(m *(1<<(mant_width - k)))
85+
else:
86+
mant = 0
87+
else:
88+
#Special case of mantissa = 0
89+
if m == 0:
90+
exp = 0
91+
mant = 0
92+
else:
93+
if m < 0:
94+
m = 0 - m
95+
mant = round_to_nearest_even((m * 2 - 1.0)*(1<<mant_width))
96+
exp = (e - 1) + bias
97+
except:
98+
print("Unknown exception", dbl, m, e, exp_width, mant_width, is_inf(dbl, exp_width), is_subnormal(dbl, exp_width), k)
99+
pass
100+
101+
#Set up sign bit first
102+
if dbl < 0:
103+
hex_rep = 1
104+
else:
105+
hex_rep = 0
106+
107+
#Shift in exponential and mantissa
108+
hex_rep = (hex_rep << exp_width) + exp
109+
hex_rep = (hex_rep << mant_width) + mant
110+
fmtspec = '{:0' + str((exp_width + mant_width + 1 + 3)/4) + 'x}'
111+
return fmtspec.format(hex_rep)

floatsip/sim/mFPMultVerifier.v

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,11 @@
22

33
module mFPMultVerifier;
44

5-
parameter pPrecision=2;
6-
parameter pManW = 52;
7-
parameter pExpW = 11;
5+
parameter pPrecision=0;
6+
parameter pManW = (pPrecision==2)?52:(pPrecision==1?23:10);
7+
parameter pExpW = (pPrecision==2)?11:(pPrecision==1?8:5);
88
parameter pPipeline=5;
9-
10-
parameter pDouble1 = 64'h3FF_0_0000_0000_0000;
11-
parameter pDouble1p5 = 64'h3FF_8_0000_0000_0000;
12-
parameter pSingle1 = 32'h3F80_0000;
13-
parameter pSingle1p5 = 32'h3FC0_0000;
14-
parameter pSingle2 = 32'h4000_0000;
9+
parameter pTestVector = (pPrecision==2)?"Mult64Data.txt":(pPrecision==1?"Mult32Data.txt":"Mult16Data.txt");
1510

1611
reg [pExpW+pManW:0] rv_A;
1712
reg [pExpW+pManW:0] rv_B;
@@ -22,6 +17,7 @@ wire [pExpW+pManW:0] wv_FltB;
2217
wire [pExpW+pManW:0] wv_FltC;
2318

2419
reg [pExpW+pManW:0] rv_FltC_D[0:pPipeline-1];
20+
reg [pExpW+pManW:0] ref_data;
2521

2622
reg r_Clk;
2723
reg r_ARst;
@@ -72,17 +68,18 @@ wire w_Inf,w_NaN;
7268
always@(posedge r_Clk)
7369
begin
7470
r_Dv <= r_GenEn;
75-
//rv_FltC_D[0] <= wv_FltC;
71+
rv_FltC_D[0] <= wv_FltC;
7672
for(I=1;I<10;I=I+1)
7773
rv_FltC_D[I]<=rv_FltC_D[I-1];
78-
ModelMultiplier(wv_FltA,wv_FltB,rv_FltC_D[0]);
74+
//ModelMultiplier(wv_FltA,wv_FltB,rv_FltC_D[0]);
75+
ModelMultiplier(wv_FltA,wv_FltB,ref_data);
7976
end
8077

8178
mFloatLoader #(.pPrecision(pPrecision),
8279
.pWidthExp(pExpW),
8380
.pWidthMan(pManW),
8481
.pDataCol(3),
85-
.pDataFile("Mult64Data.txt")) u0FPGen
82+
.pDataFile(pTestVector)) u0FPGen
8683
(
8784
.i_Clk(r_Clk),
8885
.i_ClkEn(r_GenEn),
@@ -132,7 +129,7 @@ wire w_Inf,w_NaN;
132129
else
133130
begin
134131
$display("INFINITY CHECK FAILED");
135-
//$stop;
132+
$stop;
136133
end
137134
end
138135
else if (w_NaN)

floatsip/sim/mult_data_gen.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#Python Data generator
2+
import math
3+
import random
4+
from float_util import gen_rand_float, is_subnormal, is_inf, FloatingPoint_Specification, hex_rep
5+
6+
7+
8+
coverage_counters = {'nnn' : 0}
9+
10+
def counters(a, b, p, size):
11+
def get_state(a, size):
12+
ew, mw = FloatingPoint_Specification[size]
13+
if a == 0.0:
14+
state_a = 'z'
15+
elif is_inf(a, ew):
16+
state_a = 'i'
17+
elif is_subnormal(a, ew):
18+
state_a = 's'
19+
else :
20+
state_a = 'n'
21+
return state_a
22+
state = get_state(a, size) + get_state(b, size) + get_state(p, size)
23+
try:
24+
coverage_counters[state] = coverage_counters[state] + 1
25+
except:
26+
coverage_counters[state] = 0
27+
28+
def generate_mult_test_data(size):
29+
"""
30+
Lookup the exponent width and mantissa width
31+
calculate the BIAS
32+
Find the Maximum and Minimum exponent value
33+
Generate a Random exp within the range
34+
Generate a Random mantissa value within range of (-1.0 and 1.0)
35+
a = mant * 2^exp
36+
b = mant * 2^exp
37+
p = a * b
38+
return a, b, p
39+
"""
40+
e_width, m_width = FloatingPoint_Specification[size]
41+
42+
a = gen_rand_float(size)
43+
b = gen_rand_float(size)
44+
45+
p = a * b
46+
47+
#Check subnormal value and round product to 0
48+
#The core is supposed to detect subnormal input
49+
if is_subnormal(a, e_width) or is_subnormal(b, e_width) or is_subnormal(p, e_width):
50+
p = 0.0
51+
52+
return a, b, p
53+
54+
55+
def main():
56+
#Seeding
57+
random.seed(1.0)
58+
total_N = 100000
59+
for size, (e_width, m_width) in FloatingPoint_Specification.items():
60+
print("Test vector for size ", size)
61+
with open('Mult' + str(size) + 'Data.txt', 'w') as f:
62+
with open('Mult' + str(size) + 'Real.txt', 'w') as r:
63+
for id in range(0, total_N):
64+
a, b, p = generate_mult_test_data(size)
65+
counters(a, b, p, size)
66+
r.write('{:02x} {:<+16e} {} {:<+16e} {} {:<+16e} {}\n'.format(id, a, math.frexp(a), b, math.frexp(b), p, math.frexp(p)))
67+
f.write('{:02x} {:s} {:s} {:s}\n'.format(id, hex_rep(a, e_width, m_width), hex_rep(b, e_width, m_width), hex_rep(p, e_width, m_width)))
68+
if ( id % (total_N/100)) == 0:
69+
print(id/(total_N/100))
70+
r.close()
71+
f.close()
72+
print("Coverage", coverage_counters)
73+
74+
75+
main()

0 commit comments

Comments
 (0)