-
Notifications
You must be signed in to change notification settings - Fork 152
/
blockwidth.py
executable file
·115 lines (90 loc) · 3.13 KB
/
blockwidth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/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
'''
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()