1#!/usr/bin/env python3 2 3import os, sys, re 4 5device = "up5k" 6 7pins = "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() 8 9# This script is designed to determine the routing of 5k SPRAM signals, 10# and the location of the enable config bits 11 12spram_locs = [(0, 0, 1), (0, 0, 2), (25, 0, 3), (25, 0, 4)] 13#spram_locs = [(0, 0, 1)] 14spram_data = { } 15 16spram_signals = ["WREN", "CHIPSELECT", "CLOCK", "STANDBY", "SLEEP", "POWEROFF"] 17 18for i in range(14): 19 spram_signals.append("ADDRESS[%d]" % i) 20 21for i in range(16): 22 spram_signals.append("DATAIN[%d]" % i) 23 24for i in range(16): 25 spram_signals.append("DATAOUT[%d]" % i) 26 27for i in range(4): 28 spram_signals.append("MASKWREN[%d]" % i) 29 30fuzz_options = ["ADDRESS", "DATAIN", "MASKWREN", "DATAOUT"] 31 32#Parse the output of an icebox vlog file to determine connectivity 33def parse_vlog(f, pin2net, net_map): 34 current_net = None 35 36 for line in f: 37 m = re.match(r"wire ([a-zA-Z0-9_]+);", line) 38 if m: 39 net = m.group(1) 40 mp = re.match(r"pin_([a-zA-Z0-9]+)", net) 41 if mp: 42 pin = mp.group(1) 43 if pin in pin2net: 44 current_net = pin2net[pin] 45 else: 46 current_net = None 47 else: 48 current_net = None 49 elif current_net is not None: 50 m = re.match(r"// \((\d+), (\d+), '([a-zA-Z0-9_/]+)'\)", line) 51 if m: 52 x = int(m.group(1)) 53 y = int(m.group(2)) 54 net = m.group(3) 55 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")): 56 net_map[current_net].add((x, y, net)) 57def parse_exp(f): 58 current_x = 0 59 current_y = 0 60 bits = set() 61 for line in f: 62 splitline = line.split(' ') 63 if splitline[0].endswith("_tile"): 64 current_x = int(splitline[1]) 65 current_y = int(splitline[2]) 66 elif splitline[0] == "IpConfig": 67 if splitline[1][:5] == "CBIT_": 68 bitidx = int(splitline[1][5:]) 69 bits.add((current_x, current_y, splitline[1].strip())) 70 return bits 71 72if not os.path.exists("./work_spram"): 73 os.mkdir("./work_spram") 74 75for loc in spram_locs: 76 x, y, z = loc 77 net_map = {} 78 for sig in spram_signals: 79 net_map[sig] = set() 80 net_map["SPRAM_EN"] = set() # actually a CBIT not a net 81 82 for n in fuzz_options: 83 with open("./work_spram/spram.v","w") as f: 84 print(""" 85 module top( 86 input WREN, 87 input CHIPSELECT, 88 input CLOCK, 89 input STANDBY, 90 input SLEEP, 91 input POWEROFF, 92 """, file=f) 93 if n == "ADDRESS": 94 print("\t\t\tinput [13:0] ADDRESS,", file=f) 95 if n == "DATAIN": 96 print("\t\t\tinput [15:0] DATAIN,", file=f) 97 if n == "MASKWREN": 98 print("\t\t\tinput [3:0] MASKWREN,", file=f) 99 if n == "DATAOUT": 100 print("\t\t\toutput [15:0] DATAOUT);", file=f) 101 else: 102 print("\t\t\toutput [0:0] DATAOUT);", file=f) #some dataout is always required to prevent optimisation away 103 104 addr_net = "ADDRESS" if n == "ADDRESS" else "" 105 din_net = "DATAIN" if n == "DATAIN" else "" 106 mwren_net = "MASKWREN" if n == "MASKWREN" else "" 107 108 print(""" 109 SB_SPRAM256KA spram_i 110 ( 111 .ADDRESS(%s), 112 .DATAIN(%s), 113 .MASKWREN(%s), 114 .WREN(WREN), 115 .CHIPSELECT(CHIPSELECT), 116 .CLOCK(CLOCK), 117 .STANDBY(STANDBY), 118 .SLEEP(SLEEP), 119 .POWEROFF(POWEROFF), 120 .DATAOUT(DATAOUT) 121 ); 122 """ % (addr_net, din_net, mwren_net), file=f) 123 print("endmodule",file=f) 124 pin2net = {} 125 with open("./work_spram/spram.pcf","w") as f: 126 temp_pins = list(pins) 127 for sig in spram_signals: 128 if sig.startswith("ADDRESS") and n != "ADDRESS": 129 continue 130 if sig.startswith("DATAIN") and n != "DATAIN": 131 continue 132 if sig.startswith("MASKWREN") and n != "MASKWREN": 133 continue 134 if sig.startswith("DATAOUT") and n != "DATAOUT" and sig != "DATAOUT[0]": 135 continue 136 137 if len(temp_pins) == 0: 138 sys.stderr.write("ERROR: no remaining pins to alloc") 139 sys.exit(1) 140 141 pin = temp_pins.pop() 142 pin2net[pin] = sig 143 print("set_io %s %s" % (sig, pin), file=f) 144 print("set_location spram_i %d %d %d" % loc, file=f) 145 retval = os.system("bash ../../icecube.sh -" + device + " ./work_spram/spram.v > ./work_spram/icecube.log 2>&1") 146 if retval != 0: 147 sys.stderr.write('ERROR: icecube returned non-zero error code\n') 148 sys.exit(1) 149 retval = os.system("../../../icebox/icebox_explain.py ./work_spram/spram.asc > ./work_spram/spram.exp") 150 if retval != 0: 151 sys.stderr.write('ERROR: icebox_explain returned non-zero error code\n') 152 sys.exit(1) 153 retval = os.system("../../../icebox/icebox_vlog.py -l ./work_spram/spram.asc > ./work_spram/spram.vlog") 154 if retval != 0: 155 sys.stderr.write('ERROR: icebox_vlog returned non-zero error code\n') 156 sys.exit(1) 157 with open("./work_spram/spram.vlog", "r") as f: 158 parse_vlog(f, pin2net, net_map) 159 bits = [] 160 with open("./work_spram/spram.exp", "r") as f: 161 bits = parse_exp(f) 162 net_map["SPRAM_EN"].update(bits) 163 spram_data[loc] = net_map 164 165with open(device + "_spram_data.txt", "w") as f: 166 for loc in spram_data: 167 print("\t(%d, %d, %d): {" % loc, file=f) 168 data = spram_data[loc] 169 for net in sorted(data): 170 cnets = [] 171 for cnet in data[net]: 172 cnets.append("(%d, %d, \"%s\")" % cnet) 173 print("\t\t%s %s, " % (("\"" + net.replace("[","_").replace("]","") + "\":").ljust(24), " ".join(cnets)), file=f) 174 print("\t},", file=f) 175