mirror of https://github.com/YosysHQ/icestorm.git
175 lines
6.4 KiB
Python
Executable File
175 lines
6.4 KiB
Python
Executable File
#!/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["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["SPRAM_EN"].update(bits)
|
|
spram_data[loc] = net_map
|
|
|
|
with open(device + "_spram_data.txt", "w") as f:
|
|
for loc in spram_data:
|
|
print("\t(%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\t%s %s, " % (("\"" + net.replace("[","_").replace("]","") + "\":").ljust(24), " ".join(cnets)), file=f)
|
|
print("\t},", file=f)
|