aboutsummaryrefslogtreecommitdiffstats
path: root/icefuzz/tests/rgb_drv_cbit/fuzz_rgb_drv_cbit.py
blob: 57f69b4bb2d27e262c8f45a3ce51e718372b6ff9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#!/usr/bin/env python3

import os, sys
# SB_RGB_DRV automatic fuzzing script

device = "u4k"

# SB_RGB_DRV config bits to be fuzzed
# These must be in an order such that a config with bit i set doesn't set any other undiscovered bits yet


fuzz_bits = [
    "RGB0_CURRENT_0",
    "RGB0_CURRENT_1",
    "RGB0_CURRENT_2",
    "RGB0_CURRENT_3",
    "RGB0_CURRENT_4",
    "RGB0_CURRENT_5",

    "RGB1_CURRENT_0",
    "RGB1_CURRENT_1",
    "RGB1_CURRENT_2",
    "RGB1_CURRENT_3",
    "RGB1_CURRENT_4",
    "RGB1_CURRENT_5",

    "RGB2_CURRENT_0",
    "RGB2_CURRENT_1",
    "RGB2_CURRENT_2",
    "RGB2_CURRENT_3",
    "RGB2_CURRENT_4",
    "RGB2_CURRENT_5"
]


# Boilerplate code based on the icefuzz script
code_prefix = """
module top(
    input curren,
    input rgbleden,
    input r_in,
    input g_in,
    input b_in,
    output r_led,
    output g_led,
    output b_led);
"""

def get_param_value(param_name, param_size, fuzz_bit):
    param = "\"0b";
    #In the RGB driver, once bit i of a current parameter is set i-1..0 must also be set
    is_high = False
    for i in range(param_size - 1, -1, -1):
        if fuzz_bit == param_name + "_" + str(i) or is_high:
            param += '1'
            is_high = True
        else:
            param += '0'
    param += "\""
    return param
def inst_rgb(fuzz_bit):
    v = ""
    v += """wire ledpu;
        SB_LED_DRV_CUR led_cur_inst (
          .EN(curren),
          .LEDPU(ledpu));
"""
    v += """SB_RGB_DRV rgb_inst (
        .RGBPU(ledpu),
        .RGBLEDEN(rgbleden),
        .RGB0PWM(r_in),
        .RGB1PWM(g_in),
        .RGB2PWM(b_in),
        .RGB0(r_led),
        .RGB1(g_led),
        .RGB2(b_led)
      );
"""

    v += "defparam rgb_inst.RGB0_CURRENT = " + get_param_value("RGB0_CURRENT", 6, fuzz_bit) + ";\n"
    v += "defparam rgb_inst.RGB1_CURRENT = " + get_param_value("RGB1_CURRENT", 6, fuzz_bit) + ";\n"
    v += "defparam rgb_inst.RGB2_CURRENT = " + get_param_value("RGB2_CURRENT", 6, fuzz_bit) + ";\n"

    return v;

def make_vlog(fuzz_bit):
    vlog = code_prefix
    vlog += inst_rgb(fuzz_bit)
    vlog += "endmodule"
    return vlog

known_bits = []

# Set to true to continue even if multiple bits are changed (needed because
# of the issue discusssed below)
show_all_bits = False #TODO: make this an argument

#HACK: icecube doesn't let you set all of the config bits to 0,
#which makes fuzzing early on annoying as there is never a case
#with just 1 bit set. So a tiny bit of semi-manual work is needed
#first to discover this (basically run this script with show_all_bits=True
#and look for the stuck bit)
#TODO: clever code could get rid of this
rgb_drv_en_bit = {
    "u4k" : (0, 18, 5)
}

led_drv_cur_en_bit = {
    "u4k" : (25, 19, 5)
}

#Return a list of RGB_DRIVER config bits in the format (x, y, bit)
def parse_exp(expfile):
    current_x = 0
    current_y = 0
    bits = []
    with open(expfile, 'r') as f:
        for line in f:
            splitline = line.split(' ')
            if splitline[0].endswith("_tile"):
                current_x = int(splitline[1])
                current_y = int(splitline[2])
            elif splitline[0] == "IpConfig":
                if splitline[1][:5] == "CBIT_":
                    bitidx = int(splitline[1][5:])
                    bits.append((current_x, current_y, bitidx))
    return bits

#Convert a bit tuple as returned from the above to a nice string
def bit_to_str(bit):
    return "(%d, %d, \"CBIT_%d\")" % bit

#The main fuzzing function
def do_fuzz():
    if not os.path.exists("./work_rgb_drv"):
        os.mkdir("./work_rgb_drv")
    known_bits.append(rgb_drv_en_bit[device])
    known_bits.append(led_drv_cur_en_bit[device])
    with open("rgb_drv_data_" + device + ".txt", 'w') as dat:
        for fuzz_bit in fuzz_bits:
            vlog = make_vlog(fuzz_bit)
            with open("./work_rgb_drv/rgb_drv.v", 'w') as f:
                f.write(vlog)
            with open("./work_rgb_drv/rgb_drv.pcf", 'w') as f:
                f.write("""
set_io r_led 39
set_io g_led 40
set_io b_led 41
                """)
            retval = os.system("bash ../../icecube.sh -" + device + " ./work_rgb_drv/rgb_drv.v > ./work_rgb_drv/icecube.log 2>&1")
            if retval != 0:
                sys.stderr.write('ERROR: icecube returned non-zero error code\n')
                sys.exit(1)
            retval = os.system("../../../icebox/icebox_explain.py ./work_rgb_drv/rgb_drv.asc > ./work_rgb_drv/rgb_drv.exp")
            if retval != 0:
                sys.stderr.write('ERROR: icebox_explain returned non-zero error code\n')
                sys.exit(1)
            rgb_bits = parse_exp("./work_rgb_drv/rgb_drv.exp")
            new_bits = []
            for set_bit in rgb_bits:
                if not (set_bit in known_bits):
                    new_bits.append(set_bit)
            if len(new_bits) == 0:
                sys.stderr.write('ERROR: no new bits set when setting config bit ' + fuzz_bit + '\n')
                sys.exit(1)
            if len(new_bits) > 1:
                sys.stderr.write('ERROR: multiple new bits set when setting config bit ' + fuzz_bit + '\n')
                for bit in new_bits:
                    sys.stderr.write('\t' + bit_to_str(bit) + '\n')
                if not show_all_bits:
                    sys.exit(1)
            if len(new_bits) == 1:
                known_bits.append(new_bits[0])
                if fuzz_bit == "RGB0_CURRENT_0":
                    print(("\"RGB_DRV_EN\":").ljust(24) + bit_to_str(rgb_drv_en_bit[device]) + ",")
                    dat.write(("\"RGB_DRV_EN\":").ljust(24) + bit_to_str(rgb_drv_en_bit[device]) + ",\n")
                    print(("\"LED_DRV_CUR_EN\":").ljust(24) + bit_to_str(led_drv_cur_en_bit[device]) + ",")
                    dat.write(("\"LED_DRV_CUR_EN\":").ljust(24) + bit_to_str(led_drv_cur_en_bit[device]) + ",\n")
                print(("\"" + fuzz_bit + "\":").ljust(24) + bit_to_str(new_bits[0]) + ",")
                dat.write(("\"" + fuzz_bit + "\":").ljust(24) + bit_to_str(new_bits[0]) + ",\n")
do_fuzz()