Merge pull request #1614 from antmicro/add-gtp-ports-attrs-file
gtp: generate attributes and ports files to add to the db
diff --git a/docs/dev_database/common/cell_data.rst b/docs/dev_database/common/cell_data.rst
new file mode 100644
index 0000000..07dbf8d
--- /dev/null
+++ b/docs/dev_database/common/cell_data.rst
@@ -0,0 +1,82 @@
+===============
+cell data files
+===============
+
+The *cell data* files are meant for specific primitives which have a common attribute format. The data contained in these files is generated/copied from the corresponding primitives' fuzzers.
+
+Naming convention
+-----------------
+
+The naming scheme for the cell data files is the following::
+
+ <primitive_name>_<data_file_type>.json
+
+Example files:
+
+ - ``gtpe2_common_attrs.json``
+ - ``gtpe2_channel_ports.json``
+
+File format
+-----------
+
+There are two main data file types:
+
+ - *Ports*
+ - *Attributes*
+
+Attributes files
+~~~~~~~~~~~~~~~~
+
+This is a JSON file containing a dictionary of parameters, each one with, at most, four attributes:
+
+ - Type: one of BIN, INT, STR, BOOL.
+ - Values: all possible values that this parameter can assume. In case of `BIN` types, the values list contains only the maximum value reachable.
+ - Digits: number of digits (or bits) required to enable a parameter.
+ - Encoding: This is present only for `INT` types of parameters. These reflect the actual encoding of the parameter value in the bit array.
+
+As an example of parameter please, refer to the following::
+
+ {
+ "PLL0_REFCLK_DIV": {
+ "type": "INT",
+ "values": [1, 2],
+ "encoding": [16, 0],
+ "digits": 5
+ },
+ "RXLPMRESET_TIME": {
+ "type": "BIN",
+ "values": [127],
+ "digits": 7
+ },
+ "RX_XCLK_SEL": {
+ "type": "STR",
+ "values": ["RXREC", "RXUSR"],
+ "digits": 1
+ },
+ "TX_LOOPBACK_DRIVE_HIZ": {
+ "type": "BOOL",
+ "values": ["FALSE", "TRUE"],
+ "digits": 1
+ },
+ }
+
+Ports files
+~~~~~~~~~~~
+
+This is a JSON file containing a dictionary of ports, each one with two attributes:
+
+ - Direction: Corresponds to the port directiona and can have the ``input`` or ``output`` values.
+ - Width: Indicates the width of the port bus.
+
+As an example of parameter please, refer to the following::
+
+ {
+ "CFGRESET": {
+ "direction": "input",
+ "width": 1
+ },
+ "CLKRSVD0": {
+ "direction": "input",
+ "width": 1
+ }
+ }
diff --git a/docs/dev_database/common/index.rst b/docs/dev_database/common/index.rst
index 939999e..0817f9d 100644
--- a/docs/dev_database/common/index.rst
+++ b/docs/dev_database/common/index.rst
@@ -13,3 +13,4 @@
tile_type
ppips
mask
+ cell_data
diff --git a/fuzzers/063-gtp-common-conf/Makefile b/fuzzers/063-gtp-common-conf/Makefile
index 4e93957..f865c85 100644
--- a/fuzzers/063-gtp-common-conf/Makefile
+++ b/fuzzers/063-gtp-common-conf/Makefile
@@ -16,6 +16,7 @@
SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS))
FUZDIR ?= ${PWD}
+CELLS_DATA_DIR = ${XRAY_FAMILY_DIR}/cells_data
all: database
@@ -36,7 +37,17 @@
.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 +59,9 @@
${XRAY_MASKMERGE} ${BUILD_DIR}/mask_gtp_common.db $$(find $(SPECIMENS) -name "segdata_gtp_common*")
pushdb:
+ mkdir -p $(CELLS_DATA_DIR)
+ cp attrs.json $(CELLS_DATA_DIR)/gtpe2_common_attrs.json
+ cp $(BUILD_DIR)/gtpe2_common_ports.json $(CELLS_DATA_DIR)/gtpe2_common_ports.json
BUILD_DIR=$(BUILD_DIR) source pushdb.sh
.PHONY: database pushdb
diff --git a/fuzzers/063-gtp-common-conf/generate.py b/fuzzers/063-gtp-common-conf/generate.py
index 073d696..06cc007 100644
--- a/fuzzers/063-gtp-common-conf/generate.py
+++ b/fuzzers/063-gtp-common-conf/generate.py
@@ -62,6 +62,8 @@
tile_type = params_dict["tile_type"]
params_list = params_dict["params"]
+ sites_in_tile = dict()
+
for params in params_list:
site = params["site"]
tile = params["tile"]
@@ -69,6 +71,8 @@
if "GTPE2_COMMON" not in site:
continue
+ sites_in_tile[tile] = site
+
in_use = params["IN_USE"]
segmk.add_site_tag(site, "IN_USE", in_use)
@@ -109,7 +113,7 @@
"BOTH_GTREFCLK_USED"]:
segmk.add_site_tag(site, param, params[param])
- segmk.add_tile_tag(tile, "ENABLE_DRP", params["ENABLE_DRP"])
+ segmk.add_site_tag(site, "ENABLE_DRP", params["ENABLE_DRP"])
for params in params_list:
site = params["site"]
@@ -132,9 +136,11 @@
value=params["CLKSWING_CFG"], digits=2)[::-1]
]
+ gtp_common_site = sites_in_tile[tile]
for i in range(2):
- segmk.add_tile_tag(
- tile, "IBUFDS_GTE2.CLKSWING_CFG[%u]" % (i), bitstr[i])
+ segmk.add_site_tag(
+ gtp_common_site, "IBUFDS_GTE2.CLKSWING_CFG[%u]" % (i),
+ bitstr[i])
if tile_type.startswith("GTP_COMMON_MID"):
bitfilter = bitfilter_gtp_common_mid
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 0000000..75f7c7f
--- /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 ebf729c..ecc6eb9 100644
--- a/fuzzers/064-gtp-channel-conf/Makefile
+++ b/fuzzers/064-gtp-channel-conf/Makefile
@@ -16,6 +16,7 @@
SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS))
FUZDIR ?= ${PWD}
+CELLS_DATA_DIR = ${XRAY_FAMILY_DIR}/cells_data
all: database
@@ -34,7 +35,17 @@
.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 +57,9 @@
${XRAY_MASKMERGE} ${BUILD_DIR}/mask_gtp_channelx.db $$(find $(SPECIMENS) -name "segdata_gtp_channel_[0123]*")
pushdb:
+ mkdir -p $(CELLS_DATA_DIR)
+ cp attrs.json $(CELLS_DATA_DIR)/gtpe2_channel_attrs.json
+ cp $(BUILD_DIR)/gtpe2_channel_ports.json $(CELLS_DATA_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 0000000..f847924
--- /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 0000000..e31600c
--- /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()