aboutsummaryrefslogtreecommitdiffstats
path: root/icefuzz/tests/spram/fuzz_spram.py
blob: 33e62cb85d179d39c8c39147b71108929b6348f4 (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
#!/usr/bin/env python3

import os, sys, re

device = "up5k"

pins = "2 3 4 6 9 10 11 12 13 18 19 20 21 25 26 27 28 31 32 34 35 36 37 38 42 43 44 45 46 47 48".split()

# This script is designed to determine the routing of 5k SPRAM signals,
# and the location of the enable config bits

spram_locs = [(0, 0, 1), (0, 0, 2), (25, 0, 3), (25, 0, 4)]
#spram_locs = [(0, 0, 1)]
spram_data = { }

spram_signals = ["WREN", "CHIPSELECT", "CLOCK", "STANDBY", "SLEEP", "POWEROFF"]

for i in range(14):
    spram_signals.append("ADDRESS[%d]" % i)
    
for i in range(16):
    spram_signals.append("DATAIN[%d]" % i)
    
for i in range(16):
    spram_signals.append("DATAOUT[%d]" % i)
    
for i in range(4):
    spram_signals.append("MASKWREN[%d]" % i)
    
fuzz_options = ["ADDRESS", "DATAIN", "MASKWREN", "DATAOUT"]

#Parse the output of an icebox vlog file to determine connectivity
def parse_vlog(f, pin2net, net_map):
    current_net = None
    
    for line in f:
        m = re.match(r"wire ([a-zA-Z0-9_]+);", line)
        if m:
            net = m.group(1)
            mp = re.match(r"pin_([a-zA-Z0-9]+)", net)
            if mp:
                pin = mp.group(1)
                if pin in pin2net:
                    current_net = pin2net[pin]
                else:
                    current_net = None
            else:
                current_net = None
        elif current_net is not None:
            m = re.match(r"// \((\d+), (\d+), '([a-zA-Z0-9_/]+)'\)", line)
            if m:
                x = int(m.group(1))
                y = int(m.group(2)) 
                net = m.group(3)
                if not (net.startswith("sp") or net.startswith("glb") or net.startswith("neigh") or net.startswith("io") or net.startswith("local") or net.startswith("fabout")):
                    net_map[current_net].add((x, y, net))
def parse_exp(f):
    current_x = 0
    current_y = 0
    bits = set()
    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.add((current_x, current_y, splitline[1].strip()))    
    return bits
            
if not os.path.exists("./work_spram"):
    os.mkdir("./work_spram")

for loc in spram_locs:
    x, y, z = loc
    net_map = {}
    for sig in spram_signals:
        net_map[sig] = set()
    net_map["C_SPRAM_EN"] = set() # actually a CBIT not a net
    
    for n in fuzz_options:
        with open("./work_spram/spram.v","w") as f:
            print("""
            module top(
            input WREN,
            input CHIPSELECT,
            input CLOCK,
            input STANDBY,
            input SLEEP,
            input POWEROFF,
            """, file=f)
            if n == "ADDRESS":
                print("\t\t\tinput [13:0] ADDRESS,", file=f)
            if n == "DATAIN":
                print("\t\t\tinput [15:0] DATAIN,", file=f)
            if n == "MASKWREN":
                print("\t\t\tinput [3:0] MASKWREN,", file=f)
            if n == "DATAOUT":
                print("\t\t\toutput [15:0] DATAOUT);", file=f)
            else:
                print("\t\t\toutput [0:0] DATAOUT);", file=f) #some dataout is always required to prevent optimisation away
            
            addr_net = "ADDRESS" if n == "ADDRESS" else ""
            din_net = "DATAIN" if n == "DATAIN" else ""
            mwren_net = "MASKWREN" if n == "MASKWREN" else ""
                
            print("""
            SB_SPRAM256KA spram_i
              (
                .ADDRESS(%s),
                .DATAIN(%s),
                .MASKWREN(%s),
                .WREN(WREN),
                .CHIPSELECT(CHIPSELECT),
                .CLOCK(CLOCK),
                .STANDBY(STANDBY),
                .SLEEP(SLEEP),
                .POWEROFF(POWEROFF),
                .DATAOUT(DATAOUT)
              );
            """ % (addr_net, din_net, mwren_net), file=f)
            print("endmodule",file=f)
        pin2net = {}
        with open("./work_spram/spram.pcf","w") as f:
            temp_pins = list(pins)
            for sig in spram_signals:
                if sig.startswith("ADDRESS") and n != "ADDRESS":
                    continue
                if sig.startswith("DATAIN") and n != "DATAIN":
                    continue
                if sig.startswith("MASKWREN") and n != "MASKWREN":
                    continue
                if sig.startswith("DATAOUT") and n != "DATAOUT" and sig != "DATAOUT[0]":
                    continue
                
                if len(temp_pins) == 0:
                    sys.stderr.write("ERROR: no remaining pins to alloc")
                    sys.exit(1)
                
                pin = temp_pins.pop()
                pin2net[pin] = sig
                print("set_io %s %s" % (sig, pin), file=f)
            print("set_location spram_i %d %d %d" % loc, file=f)
        retval = os.system("bash ../../icecube.sh -" + device + " ./work_spram/spram.v > ./work_spram/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_spram/spram.asc > ./work_spram/spram.exp")
        if retval != 0:
            sys.stderr.write('ERROR: icebox_explain returned non-zero error code\n')
            sys.exit(1)
        retval = os.system("../../../icebox/icebox_vlog.py -l ./work_spram/spram.asc > ./work_spram/spram.vlog")
        if retval != 0:
            sys.stderr.write('ERROR: icebox_vlog returned non-zero error code\n')
            sys.exit(1)
        with open("./work_spram/spram.vlog", "r") as f:
            parse_vlog(f, pin2net, net_map)
        bits = []
        with open("./work_spram/spram.exp", "r") as f:
            bits = parse_exp(f)
        net_map["C_SPRAM_EN"].update(bits)
    spram_data[loc] = net_map         

with open(device + "_spram_data.txt", "w") as f:
    for loc in spram_data:
        print("SPRAM %d %d %d" % loc, file=f)
        data = spram_data[loc]
        for net in sorted(data):
            cnets = []
            for cnet in data[net]:
                cnets.append("(%d, %d, %s)" % cnet)
            print("\t%s: %s" % (net, " ".join(cnets)), file=f)