mirror of https://github.com/openXC7/prjxray.git
107 lines
2.9 KiB
Python
Executable File
107 lines
2.9 KiB
Python
Executable File
#!/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%02X' % (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()
|