diff --git a/fuzzers/076-ps7/Makefile b/fuzzers/076-ps7/Makefile new file mode 100644 index 00000000..f58aae52 --- /dev/null +++ b/fuzzers/076-ps7/Makefile @@ -0,0 +1,30 @@ +N := 1 +SPECIMENS := $(addprefix build/specimen_,$(shell seq -f '%03.0f' $(N))) +SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) + +database: $(SPECIMENS_OK) + +pushdb: build/ps7_ports.json + mkdir -p ${XRAY_FAMILY_DIR} + cp build/ps7*.json ${XRAY_FAMILY_DIR}/ + +$(SPECIMENS_OK): + bash generate.sh $(subst /OK,,$@) + touch $@ + +build/ps7_pins.csv: $(SPECIMENS_OK) + cp build/specimen_001/ps7_pins.csv build/ + +build/ps7_ports.json: build/ps7_pins.csv + python3 make_ports.py $< $@ + +run: + $(MAKE) clean + $(MAKE) database + $(MAKE) pushdb + touch run.ok + +clean: + rm -rf build run.ok + +.PHONY: database pushdb run clean diff --git a/fuzzers/076-ps7/README.md b/fuzzers/076-ps7/README.md new file mode 100644 index 00000000..571b84dc --- /dev/null +++ b/fuzzers/076-ps7/README.md @@ -0,0 +1,3 @@ +# PS7 verilog cell definition extractor + +Extracts all pins of the PS7 bel from Vivado, groups them into ports, writes them to a JSON file. diff --git a/fuzzers/076-ps7/generate.sh b/fuzzers/076-ps7/generate.sh new file mode 100644 index 00000000..e6b0e2c6 --- /dev/null +++ b/fuzzers/076-ps7/generate.sh @@ -0,0 +1,6 @@ +#!/bin/bash -x + +source ${XRAY_GENHEADER} + +${XRAY_VIVADO} -mode batch -source $FUZDIR/generate.tcl + diff --git a/fuzzers/076-ps7/generate.tcl b/fuzzers/076-ps7/generate.tcl new file mode 100644 index 00000000..f8a55556 --- /dev/null +++ b/fuzzers/076-ps7/generate.tcl @@ -0,0 +1,19 @@ +create_project -force -name design -part $::env(XRAY_PART) +set_property design_mode PinPlanning [current_fileset] +open_io_design -name io_1 + +set fp [open ps7_pins.csv w] +puts $fp "name,is_input,is_output,is_bidir" + +set pins [get_bel_pins -of_objects [get_bels -of_objects [get_sites PS7* -of_objects [get_tiles PSS*]]]] +foreach pin $pins { + + set pin_name [lindex [split $pin "/"] 2] + set is_input [get_property IS_INPUT $pin] + set is_output [get_property IS_OUTPUT $pin] + set is_bidir [get_property IS_BIDIR $pin] + + puts $fp "$pin_name,$is_input,$is_output,$is_bidir" +} + +close $fp diff --git a/fuzzers/076-ps7/make_ports.py b/fuzzers/076-ps7/make_ports.py new file mode 100644 index 00000000..1f4f169c --- /dev/null +++ b/fuzzers/076-ps7/make_ports.py @@ -0,0 +1,131 @@ +#!/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() diff --git a/fuzzers/Makefile b/fuzzers/Makefile index b58659b9..cedde639 100644 --- a/fuzzers/Makefile +++ b/fuzzers/Makefile @@ -120,6 +120,9 @@ $(eval $(call fuzzer,072-ordered_wires,)) $(eval $(call fuzzer,073-get_counts,)) $(eval $(call fuzzer,074-dump_all,005-tilegrid 072-ordered_wires)) $(eval $(call fuzzer,075-pins,)) +ifeq ($(XRAY_DATABASE),zynq7) +$(eval $(call fuzzer,076-ps7,)) +endif endif endif $(eval $(call fuzzer,100-dsp-mskpat,005-tilegrid))