Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
d765214e1This file is pinned to the selected release. Download the original to open it in your design tool.
#!/usr/bin/env python3
# Turn KiCad netlist into a PCF file for icestorm
import argparse
import re
import shlex
from collections import OrderedDict
def sanitize_net_name(s):
s = s.replace("~", "")
s = re.sub(r"(\d+)$", r"[\1]", s)
return s
def natural_key(s):
return tuple(int(x) if x.isdigit() else x for x in re.split(r"(\d+)", s))
def extract_nets(fh, ref, filters):
nets = []
name = None
namevalid = False
for l in fh:
m = re.match(r"^\s*\(net \([^\)]*\) \(name ([^\)]+)\)", l)
if m:
name = m.group(1).strip().strip("/").lower()
namevalid = not any(name.startswith(s) for s in [
"\"net", "+", "-", "gnd", "vcc", "vdd", "vss", *filters
])
elif namevalid:
m = re.match(r"^\s*\(node \(ref ([^\)]+)\) \(pin ([^\)]+)\)", l)
if m and m.group(1) == ref:
nets.append((name, m.group(2)))
return nets
def align_buses(nets):
buses = OrderedDict()
onets = []
# First figure out what is/isn't a bus
for net in nets:
if "[" in net[0]:
busname = net[0].split("[")[0]
if busname not in buses:
buses[busname] = []
buses[busname].append(net)
else:
onets.append(net)
# Then right-justify the buses
for busname, bus in buses.items():
indices = list(int(net[0].split('[')[1].strip(']')) for net in bus)
lsb = min(indices)
for index, net in zip(indices, bus):
onets.append(("{}[{}]".format(busname, index - lsb), net[1]))
return onets
def write_pcf(fh, nets):
fh.write("# Generated with extract_ref_nets\n\n")
for name, loc in sorted(nets, key = lambda x: natural_key(x[0])):
fh.write("set_io {:<20} {}\n".format(name, loc))
def main():
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("netfile", help="Path to KiCad .net file")
parser.add_argument("ref", help="Component reference whose named nets will be extracted")
parser.add_argument("--output", "-o", help="Output file name")
parser.add_argument("--filters", "-f", help="-f \"abc xyz\": filter out nets beginning with abc or xyz")
args = parser.parse_args()
opath = "chip.pcf" if args.output is None else args.output
filters = [] if args.filters is None else shlex.split(args.filters)
with open(args.netfile) as ifile:
nets = extract_nets(ifile, args.ref, filters)
nets = map(lambda n: (sanitize_net_name(n[0]), n[1]), nets)
nets = align_buses(nets)
with open(opath, "w") as ofile:
write_pcf(ofile, nets)
if __name__ == "__main__":
main()