blob: aa1eba011fde380aaa6a4a60e156ebbf9df69575 [file] [log] [blame]
#!/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 performs the analysis of disassembled bitstream and design information.
It correlates presence/absence of particular fasm features in the bitstream
with presence/absence of a particular IOB type. It also checks for features
that are set for unused IOBs that are in the same bank as the used ones.
The list of available fasm features is read from the prjxray database. The
analysis result is written to a CSV file.
"""
import os
import argparse
import json
import random
from collections import defaultdict
from prjxray import util
import fasm
# =============================================================================
def load_iob_segbits():
"""
Loads IOB segbits from the database to get fasm feature list.
This function assumes:
- LIOB33/RIOB33 have the same features.
- IOB_Y0 and IOB_Y1 have the same features (at least those of interest).
"""
features = []
fname = os.path.join(util.get_db_root(), "segbits_liob33.db")
with open(fname, "r") as fp:
for line in fp:
line = line.strip()
if len(line) == 0:
continue
# Parse the line
fields = line.split(maxsplit=1)
feature = fields[0]
bits = fields[1]
# Parse the feature
parts = feature.split(".", maxsplit=3)
if len(parts) >= 3 and parts[1] == "IOB_Y0":
features.append(".".join(parts[2:]))
return features
def correlate_features(features, tile, site, set_features):
"""
Correlate each feature with the fasm disassembly for given tile/site.
Given a set of all possible fasm features (for an IOB) in the first
argument, checks whether they are set or cleared for the given tile+site in
a design. The parameter set_features contains fasm dissassembly of the
design.
Returns a list of tuples with feature names and whether they are set or not.
"""
result = []
for feature in features:
full_feature = "{}.{}.{}".format(tile, site, feature)
if full_feature in set_features:
result.append((
feature,
True,
))
else:
result.append((
feature,
False,
))
return result
def run():
"""
Main.
"""
# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument(
"--design", type=str, required=True, help="Design JSON file")
parser.add_argument(
"--fasm", type=str, required=True, help="Decoded fasm file")
parser.add_argument(
"-o", type=str, default="results.csv", help="Output CSV file")
parser.add_argument("-j", type=str, default=None, help="Output JSON file")
args = parser.parse_args()
# Load IOB features
features = load_iob_segbits()
# Load the design data
with open(args.design, "r") as fp:
design = json.load(fp)
# Load disassembled fasm
fasm_tuples = fasm.parse_fasm_filename(args.fasm)
set_features = fasm.fasm_tuple_to_string(fasm_tuples).split("\n")
# Correlate features for given IOB types
results = []
for region in design:
result = dict(region["iosettings"])
for l in ["input", "output", "inout", "unused_sites"]:
# TODO: Check if this is true eg. for all unused sites, not just
# one random site.
tile, site = random.choice(region[l]).split(".")
matches = correlate_features(features, tile, site, set_features)
result[l] = matches
results.append(result)
# Save results
if args.j:
with open(args.j, "w") as fp:
json.dump(results, fp, indent=2, sort_keys=True)
# Save results to CSV
with open(args.o, "w") as fp:
csv_data = defaultdict(lambda: {})
# Collect data
for result in results:
iostandard = result["iostandard"]
drive = result["drive"]
slew = result["slew"]
if drive is None:
drive = "_FIXED"
iosettings = "{}.I{}.{}".format(iostandard, drive, slew)
is_diff = "DIFF" in iostandard
for feature in sorted(features):
I = [f[1] for f in result["input"] if f[0] == feature and f[1]]
O = [
f[1] for f in result["output"] if f[0] == feature and f[1]
]
T = [f[1] for f in result["inout"] if f[0] == feature and f[1]]
U = [
f[1]
for f in result["unused_sites"]
if f[0] == feature and f[1]
]
s = "".join(
[
"I" if len(I) > 0 else "",
"O" if len(O) > 0 else "",
"T" if len(T) > 0 else "",
"U" if len(U) > 0 else "",
])
csv_data[iosettings][feature] = s
# Write header
line = ["iosettings"] + sorted(features)
fp.write(",".join(line) + "\n")
# Write data
for iosettings in sorted(csv_data.keys()):
data = csv_data[iosettings]
line = [iosettings
] + [data[feature] for feature in sorted(features)]
fp.write(",".join(line) + "\n")
if __name__ == "__main__":
run()