diff --git a/fuzzers/063-gtp-common-conf/Makefile b/fuzzers/063-gtp-common-conf/Makefile index 4e939577..c653cccd 100644 --- a/fuzzers/063-gtp-common-conf/Makefile +++ b/fuzzers/063-gtp-common-conf/Makefile @@ -36,7 +36,17 @@ clean: .PHONY: all run clean -database: ${BUILD_DIR}/segbits_gtp_common.db +# These are pins that are hard to parse as a regexp given that the port name ends with a number, which is misinterpreted +# as the index in the port bus +SPECIAL_PINS = PLLRSVD1,PLLRSVD2,GTREFCLK0,GTREFCLK1,GTGREFCLK0,GTGREFCLK1,GTEASTREFCLK0,GTEASTREFCLK1,GTWESTREFCLK0,GTWESTREFCLK1,REFCLKOUTMONITOR0,REFCLKOUTMONITOR1 + +$(BUILD_DIR)/gtpe2_common_ports.csv: generate_ports.tcl + env FILE_NAME=$(BUILD_DIR)/gtpe2_common_pins.csv ${XRAY_VIVADO} -mode batch -source generate_ports.tcl + +$(BUILD_DIR)/gtpe2_common_ports.json: $(BUILD_DIR)/gtpe2_common_ports.csv + python3 ${XRAY_UTILS_DIR}/make_ports.py $(BUILD_DIR)/gtpe2_common_pins.csv $(BUILD_DIR)/gtpe2_common_ports.json --special-pins $(SPECIAL_PINS) + +database: ${BUILD_DIR}/segbits_gtp_common.db $(BUILD_DIR)/gtpe2_common_ports.json ${BUILD_DIR}/segbits_gtp_common.rdb: $(SPECIMENS_OK) ${XRAY_SEGMATCH} -o ${BUILD_DIR}/segbits_gtp_common.rdb $$(find $(SPECIMENS) -name "segdata_gtp_common*") @@ -48,6 +58,8 @@ ${BUILD_DIR}/segbits_gtp_common.db: ${BUILD_DIR}/segbits_gtp_common.rdb ${XRAY_MASKMERGE} ${BUILD_DIR}/mask_gtp_common.db $$(find $(SPECIMENS) -name "segdata_gtp_common*") pushdb: + cp attrs.json ${XRAY_FAMILY_DIR}/gtpe2_common_attrs.json + cp $(BUILD_DIR)/gtpe2_common_ports.json ${XRAY_FAMILY_DIR}/gtpe2_common_ports.json BUILD_DIR=$(BUILD_DIR) source pushdb.sh .PHONY: database pushdb diff --git a/fuzzers/063-gtp-common-conf/generate_ports.tcl b/fuzzers/063-gtp-common-conf/generate_ports.tcl new file mode 100644 index 00000000..75f7c7ff --- /dev/null +++ b/fuzzers/063-gtp-common-conf/generate_ports.tcl @@ -0,0 +1,36 @@ +# 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 + +proc dump_pins {file_name site_prefix} { + set fp [open $file_name w] + + puts $fp "name,is_input,is_output" + set site [lindex [get_sites $site_prefix*] 0] + + set pins [get_site_pins -of_objects $site] + foreach pin $pins { + set connected_pip [get_pips -of_objects [get_nodes -of_objects $pin]] + + if { $connected_pip == "" } { + continue + } + + set pin_name [lindex [split $pin "/"] 1] + set is_input [get_property IS_INPUT $pin] + set is_output [get_property IS_OUTPUT $pin] + + puts $fp "$pin_name,$is_input,$is_output" + } + close $fp +} + +create_project -force -name design -part $::env(XRAY_PART) +set_property design_mode PinPlanning [current_fileset] +open_io_design -name io_1 + +dump_pins $::env(FILE_NAME) GTPE2_COMMON diff --git a/fuzzers/064-gtp-channel-conf/Makefile b/fuzzers/064-gtp-channel-conf/Makefile index ebf729c9..1381816a 100644 --- a/fuzzers/064-gtp-channel-conf/Makefile +++ b/fuzzers/064-gtp-channel-conf/Makefile @@ -34,7 +34,17 @@ clean: .PHONY: all run clean -database: ${BUILD_DIR}/segbits_gtp_channelx.db +# These are pins that are hard to parse as a regexp given that the port name ends with a number, which is misinterpreted +# as the index in the port bus +SPECIAL_PINS = CLKRSVD0,CLKRSVD1,GTREFCLK0,GTREFCLK1,GTNORTHREFCLK0,GTNORTHREFCLK1,GTSOUTHREFCLK0,GTSOUTHREFCLK1,RXUSRCLK,RXUSRCLK2,TXUSRCLK,TXUSRCLK2,RXOSINTID0,PMARSVDIN0,PMARSVDIN1,PMARSVDIN2,PMARSVDIN3,PMARSVDIN4,PMARSVDOUT0,PMARSVDOUT1 + +$(BUILD_DIR)/gtpe2_channel_ports.csv: + env FILE_NAME=$(BUILD_DIR)/gtpe2_channel_pins.csv ${XRAY_VIVADO} -mode batch -source generate_ports.tcl + +$(BUILD_DIR)/gtpe2_channel_ports.json: $(BUILD_DIR)/gtpe2_channel_ports.csv + python3 ${XRAY_UTILS_DIR}/make_ports.py $(BUILD_DIR)/gtpe2_channel_pins.csv $(BUILD_DIR)/gtpe2_channel_ports.json --special-pins $(SPECIAL_PINS) + +database: ${BUILD_DIR}/segbits_gtp_channelx.db $(BUILD_DIR)/gtpe2_channel_ports.json ${BUILD_DIR}/segbits_gtp_channelx.rdb: $(SPECIMENS_OK) ${XRAY_SEGMATCH} -c 9 -o ${BUILD_DIR}/segbits_gtp_channelx.rdb $$(find $(SPECIMENS) -name "segdata_gtp_channel_[0123]*") @@ -46,6 +56,8 @@ ${BUILD_DIR}/segbits_gtp_channelx.db: ${BUILD_DIR}/segbits_gtp_channelx.rdb ${XRAY_MASKMERGE} ${BUILD_DIR}/mask_gtp_channelx.db $$(find $(SPECIMENS) -name "segdata_gtp_channel_[0123]*") pushdb: + cp attrs.json ${XRAY_FAMILY_DIR}/gtpe2_channel_attrs.json + cp $(BUILD_DIR)/gtpe2_channel_ports.json ${XRAY_FAMILY_DIR}/gtpe2_channel_ports.json BUILD_DIR=$(BUILD_DIR) source pushdb.sh .PHONY: database pushdb diff --git a/fuzzers/064-gtp-channel-conf/generate_ports.tcl b/fuzzers/064-gtp-channel-conf/generate_ports.tcl new file mode 100644 index 00000000..f8479240 --- /dev/null +++ b/fuzzers/064-gtp-channel-conf/generate_ports.tcl @@ -0,0 +1,36 @@ +# 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 + +proc dump_pins {file_name site_prefix} { + set fp [open $file_name w] + + puts $fp "name,is_input,is_output" + set site [lindex [get_sites $site_prefix*] 0] + + set pins [get_site_pins -of_objects $site] + foreach pin $pins { + set connected_pip [get_pips -of_objects [get_nodes -of_objects $pin]] + + if { $connected_pip == "" } { + continue + } + + set pin_name [lindex [split $pin "/"] 1] + set is_input [get_property IS_INPUT $pin] + set is_output [get_property IS_OUTPUT $pin] + + puts $fp "$pin_name,$is_input,$is_output" + } + close $fp +} + +create_project -force -name design -part $::env(XRAY_PART) +set_property design_mode PinPlanning [current_fileset] +open_io_design -name io_1 + +dump_pins $::env(FILE_NAME) GTPE2_CHANNEL diff --git a/utils/make_ports.py b/utils/make_ports.py new file mode 100644 index 00000000..e31600c3 --- /dev/null +++ b/utils/make_ports.py @@ -0,0 +1,108 @@ +#!/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 pin dump of the desired BEL from Vivado and groups pins into ports. + +Ports that are not connected to the PL are not included. These ports are usually test and +debug related ports, which are not useful from a P&R perspective. + +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="BEL pin dump file") + parser.add_argument( + "json", + type=str, + help="Output JSON file with BEL pins grouped into ports") + + parser.add_argument( + "--special-pins", + default="", + type=str, + required=False, + help="Some pins cannot be decoded with the regex") + + 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, "width": 0}) + + special_pins = args.special_pins.split(",") + + for pin in list(pin_dump): + pin_name = pin["name"] + + name = None + if pin_name in special_pins: + # Full match + name = pin_name + else: + # Partial match + for special_pin in special_pins: + if pin_name.startswith(special_pin): + name = special_pin + break + + if name is None: + match = BUS_REGEX.match(pin_name) + if match: + name = match.group(1) + else: + name = pin_name + + # Get direction + is_input = int(pin["is_input"]) + is_output = int(pin["is_output"]) + + if is_input: + direction = "input" + elif is_output: + direction = "output" + else: + assert False, pin + + # Add to port + port = ports[name] + + if port["direction"] is None: + port["direction"] = direction + else: + assert port["direction"] == direction, (port, direction, name) + + port["width"] += 1 + + # 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()