| #!/usr/bin/env python3 |
| # -*- coding: utf-8 -*- |
| # |
| # Copyright (C) 2017-2020 The Project X-Ray Authors. |
| # |
| # Use of this source code is governed by a ISC-style |
| # license that can be found in the LICENSE file or at |
| # https://opensource.org/licenses/ISC |
| # |
| # SPDX-License-Identifier: ISC |
| """ |
| 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() |