#!/usr/bin/env python3 """ This script loads the PS7 pin dump from Vivado and groups pins into ports. Also assigns each port a class that indicates its function. The classes are: - "normal": A port that connects to the PL (FPGA) - "test": A port used for testing, not accessible from the PL. - "debug": A debug port, not accessible. - "mio": The "mio" ports go directly to die pads, not relevant for routing. Ports are then written to a JSON file. """ import argparse import csv import json import re from collections import defaultdict # ============================================================================= def main(): BUS_REGEX = re.compile("(.*[A-Z_])([0-9]+)$") # Parse arguments parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("csv", type=str, help="PS7 pin dump file") parser.add_argument( "json", type=str, help="Output JSON file with PS7 pins grouped into ports") args = parser.parse_args() # Load pin dump with open(args.csv, "r") as fp: pin_dump = list(csv.DictReader(fp)) # Group pins into ports ports = defaultdict(lambda :{ "direction": None, "min": None, "max": None, "width": 0 }) for pin in list(pin_dump): # Get port name and signal index match = BUS_REGEX.match(pin["name"]) if match: name = match.group(1) idx = int(match.group(2)) else: name = pin["name"] idx = 0 # Get direction is_input = int(pin["is_input"]) is_output = int(pin["is_output"]) is_bidir = int(pin["is_bidir"]) if is_input and not is_output and not is_bidir: direction = "input" elif not is_input and is_output and not is_bidir: direction = "output" elif not is_input and not is_output and is_bidir: direction = "inout" else: assert False, pin # Add to port port = ports[name] if port["direction"] is None: port["direction"] = direction else: assert port["direction"] == direction if port["min"] is None: port["min"] = idx else: port["min"] = min(port["min"], idx) if port["max"] is None: port["max"] = idx else: port["max"] = max(port["max"], idx) port["width"] = port["max"] - port["min"] + 1 # Sort ports by their purpose for name, port in ports.items(): # A test pin (unconnected) if name.startswith("TEST"): cls = "test" # A debug pin (unconnected) elif name.startswith("DEBUG"): cls = "debug" # A MIO/DDR pin. elif name.startswith("MIO") or name.startswith("DDR") and \ name != "DDRARB": cls = "mio" # PS7 clock/reset elif name in ["PSCLK", "PSPORB", "PSSRSTB"]: cls = "mio" # "Normal" pin else: cls = "normal" port["class"] = cls # Write pin ports to a JSON file with open(args.json, "w") as fp: json.dump(ports, fp, indent=1, sort_keys=True) # ============================================================================= if __name__ == "__main__": main()