diff --git a/utils/blockwidth.py b/utils/blockwidth.py new file mode 100644 index 00000000..ae6758cf --- /dev/null +++ b/utils/blockwidth.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +''' +Prints minor address group sizes +If any part of an IP block is written, Vivado likes to write the entire block +This can be useful to guess the number of frames an IP block uses + +This was developed with PERFRAMECRC, but could probably be rewritten to work without it +''' + +import sys +import os +import time +import json +import subprocess +from io import StringIO + +BITTOOL = os.getenv('XRAY_BITTOOL') + + +def bit2packets(fn): + # capture_output wasn't added until 3.7, I have 3.5 + #return subprocess.run([BITTOOL, "list_config_packets", fn], capture_output=True, check=True).stdout + p = subprocess.run( + [BITTOOL, "list_config_packets", fn], + check=True, + stdout=subprocess.PIPE) + return p.stdout.decode("ascii") + + +def nominor(addr): + return addr & ~0x7f + + +def gen_frame_writes(f): + ''' + look for line triples like this + + [Write Type=1 Address= 1 Length= 1 Reg="Frame Address"] + Data in hex: + 1d + + ''' + while True: + l = f.readline() + if not l: + break + l = l.strip() + # TODO: assert that writes are always per frame CRC + if l != '[Write Type=1 Address= 1 Length= 1 Reg="Frame Address"]': + continue + assert f.readline().strip() == 'Data in hex:' + lhex = f.readline().strip() + yield int(lhex, 16) + + +def gen_major_writes(fnin): + ''' + The same address can appear twice + Ex: 0x00800000 + Moved from counter to set + ''' + last_addrs = None + last_major = None + + for this_minor in gen_frame_writes(StringIO(bit2packets(fnin))): + this_major = nominor(this_minor) + + if this_major == last_major: + # should be no gaps + last_addrs.add(this_minor) + + # addresses may skip back, but they don't seem to skip forward + # AssertionError: (0, 2, {0, 1}) + # assert (this_major - this_minor) + 1 == len(last_addrs), (this_major, len(last_addrs), last_addrs) + assert (this_major - this_minor) + 1 <= len(last_addrs), ( + this_major, len(last_addrs), last_addrs) + else: + if last_major is not None: + assert len(last_addrs) <= 0x80 + yield last_major, len(last_addrs) + + # all writes should start at base? + assert this_major == this_minor + last_major = this_major + last_addrs = set([this_minor]) + yield last_major, len(last_addrs) + + +def run(fnin, verbose=False): + for addr, nframes in gen_major_writes(fnin): + print('0x%08X: 0x%08X' % (addr, nframes)) + + +def main(): + import argparse + + parser = argparse.ArgumentParser( + description='Print PERFRAMECRC bitstream minor address gropuing') + parser.add_argument('fnin', default=None, help='input bitstream') + args = parser.parse_args() + + run(args.fnin, verbose=False) + + +if __name__ == '__main__': + main() diff --git a/utils/environment.sh b/utils/environment.sh index 5545f727..fb69da52 100644 --- a/utils/environment.sh +++ b/utils/environment.sh @@ -24,5 +24,6 @@ export XRAY_SEGMATCH="${XRAY_TOOLS_DIR}/segmatch" export XRAY_SEGPRINT="python3 ${XRAY_UTILS_DIR}/segprint.py" export XRAY_BITS2FASM="python3 ${XRAY_UTILS_DIR}/bits2fasm.py" export XRAY_FASM2FRAMES="python3 ${XRAY_UTILS_DIR}/fasm2frames.py" - +export XRAY_BITTOOL="${XRAY_TOOLS_DIR}/bittool" +export XRAY_BLOCKWIDTH="python3 ${XRAY_UTILS_DIR}/blockwidth.py"