mirror of https://github.com/openXC7/prjxray.git
checkdb: check tile overlap
Signed-off-by: John McMaster <johndmcmaster@gmail.com>
This commit is contained in:
parent
5060dae1be
commit
96ee4ac449
|
|
@ -96,3 +96,57 @@ def parse_db_line(line):
|
|||
# 100_319
|
||||
assert re.match(r'[!]*[0-9]+_[0-9]+', bit), "Invalid bit: %s" % bit
|
||||
return tag, bits, None
|
||||
|
||||
|
||||
def parse_tagbit(x):
|
||||
# !30_07
|
||||
if x[0] == '!':
|
||||
isset = False
|
||||
numstr = x[1:]
|
||||
else:
|
||||
isset = True
|
||||
numstr = x
|
||||
frame, word = numstr.split("_")
|
||||
# second part forms a tuple refereced in sets
|
||||
return (isset, (int(frame, 10), int(word, 10)))
|
||||
|
||||
|
||||
def gen_tile_bits(db_root, tilej, strict=False, verbose=False):
|
||||
'''
|
||||
For given tile yield
|
||||
(absolute address, absolute FDRI bit offset, tag)
|
||||
|
||||
For each address space
|
||||
Find applicable files
|
||||
For each tag bit in those files, calculate absolute address and bit offsets
|
||||
|
||||
Sample file names:
|
||||
segbits_clbll_l.db
|
||||
segbits_int_l.db
|
||||
segbits_bram_l.block_ram.db
|
||||
'''
|
||||
for block_type, blockj in tilej["bits"].items():
|
||||
baseaddr = int(blockj["baseaddr"], 0)
|
||||
bitbase = 32 * blockj["offset"]
|
||||
|
||||
if block_type == "CLB_IO_CLK":
|
||||
fn = "%s/segbits_%s.db" % (db_root, tilej["type"].lower())
|
||||
else:
|
||||
fn = "%s/segbits_%s.db.%s" % (
|
||||
db_root, tilej["type"].lower(), block_type.lower())
|
||||
# tilegrid runs a lot earlier than fuzzers
|
||||
# may not have been created yet
|
||||
verbose and print("Check %s: %s" % (fn, os.path.exists(fn)))
|
||||
if strict:
|
||||
assert os.path.exists(fn)
|
||||
elif not os.path.exists(fn):
|
||||
continue
|
||||
|
||||
with open(fn, "r") as f:
|
||||
for line in f:
|
||||
tag, bits, mode = parse_db_line(line)
|
||||
assert mode is None
|
||||
for bitstr in bits:
|
||||
# 31_06
|
||||
_bit_inv, (bit_addroff, bit_bitoff) = parse_tagbit(bitstr)
|
||||
yield (baseaddr + bit_addroff, bitbase + bit_bitoff, tag)
|
||||
|
|
|
|||
116
utils/checkdb.py
116
utils/checkdb.py
|
|
@ -1,93 +1,114 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
'''
|
||||
Check:
|
||||
-Individual files are valid
|
||||
-No overlap between any tile
|
||||
|
||||
TODO:
|
||||
Can we use prjxray?
|
||||
Relies on 074, which is too far into the process
|
||||
'''
|
||||
|
||||
import sys, re
|
||||
from prjxray import util
|
||||
from prjxray import db as prjxraydb
|
||||
import os
|
||||
import parsedb
|
||||
#from prjxray import db as prjxraydb
|
||||
import glob
|
||||
|
||||
|
||||
def make_tile_mask(db_root, tile_name, tilej, strict=False, verbose=False):
|
||||
'''
|
||||
Return dict
|
||||
key: (address, bit index)
|
||||
val: sample description of where it came from (there may be multiple, only one)
|
||||
'''
|
||||
|
||||
# FIXME: fix mask files https://github.com/SymbiFlow/prjxray/issues/301
|
||||
# in the meantime build them on the fly
|
||||
# We may want this to build them anyway
|
||||
|
||||
ret = dict()
|
||||
for absaddr, bitaddr, tag in util.gen_tile_bits(
|
||||
db_root, tilej, strict=strict, verbose=verbose):
|
||||
name = "%s.%s" % (tile_name, tag)
|
||||
ret.setdefault((absaddr, bitaddr), name)
|
||||
return ret
|
||||
|
||||
|
||||
def parsedb_all(db_root, verbose=False):
|
||||
'''Verify .db files are individually valid'''
|
||||
|
||||
for bit_fn in glob.glob('%s/segbits_*.db'):
|
||||
files = 0
|
||||
for bit_fn in glob.glob('%s/segbits_*.db' % db_root):
|
||||
verbose and print("Checking %s" % bit_fn)
|
||||
parsedb.run(bit_fn, fnout=None, strict=True, verbose=verbose)
|
||||
files += 1
|
||||
print("segbits_*.db: %d okay" % files)
|
||||
|
||||
for bit_fn in glob.glob('%s/mask_*.db'):
|
||||
files = 0
|
||||
for bit_fn in glob.glob('%s/mask_*.db' % db_root):
|
||||
verbose and print("Checking %s" % bit_fn)
|
||||
parsedb.run(bit_fn, fnout=None, strict=True, verbose=verbose)
|
||||
|
||||
def process_db(tile_type, process, verbose):
|
||||
#ttdb = db.get_tile_type(tile_type)
|
||||
|
||||
fns = [ttdb.tile_dbs.segbits, ttdb.tile_dbs.ppips]
|
||||
verbose and print("process_db(%s): %s" % (tile_type, fns))
|
||||
for fn in fns:
|
||||
if fn:
|
||||
with open(fn, "r") as f:
|
||||
for line in f:
|
||||
process(util.parse_db_line(line))
|
||||
files += 1
|
||||
print("mask_*.db: %d okay" % files)
|
||||
|
||||
|
||||
def check_seg_overlap(db_root, verbose=False):
|
||||
def check_tile_overlap(db, db_root, strict=False, verbose=False):
|
||||
'''
|
||||
Verifies that no two tiles use the same bit
|
||||
|
||||
Assume .db files are individually valid
|
||||
Create a mask for all the bits the tile type uses
|
||||
For each tile, create bitmasks over the entire bitstream for current part
|
||||
Throw an exception if two tiles share an address
|
||||
'''
|
||||
# key: (address, bit index)
|
||||
# val: sample description of where it came from (there may be multiple, only one)
|
||||
used = dict()
|
||||
mall = dict()
|
||||
|
||||
tiles_checked = 0
|
||||
for tile_name, tile in db.tilegrid.items():
|
||||
#ttdb = db.get_tile_type(tile["type"])
|
||||
# FIXME: check BRAM
|
||||
bitj = tile["bits"].get("CLB_IO_CLK", None)
|
||||
if not bitj:
|
||||
for tile_name, tilej in db.tilegrid.items():
|
||||
#for tile_name, tilej in [("CLBLL_L_X12Y138", db.tilegrid["CLBLL_L_X12Y138"])]:
|
||||
mtile = make_tile_mask(
|
||||
db_root, tile_name, tilej, strict=strict, verbose=verbose)
|
||||
verbose and print(
|
||||
"Checking %s, type %s, bits: %s" %
|
||||
(tile_name, tilej["type"], len(mtile)))
|
||||
if len(mtile) == 0:
|
||||
continue
|
||||
verbose and print("Checking %s, type %s" % (tile_name, tile["type"]))
|
||||
baseaddr = int(bitj["baseaddr"], 0)
|
||||
bitbase = 32 * bitj["offset"]
|
||||
|
||||
# Create tile mask
|
||||
tile_used = dict()
|
||||
def process(lparse):
|
||||
tag, bits, mode = lparse
|
||||
assert mode is None
|
||||
for (bit_addroff, bit_bitoff) in bits:
|
||||
tile_used[(baseaddr + bit_addroff, bitbase + bit_bitoff)] = "%s.%s" % (tile_name, tag)
|
||||
process_db(tile["type"], process, verbose=verbose)
|
||||
|
||||
# See if tile mask intersects any existing bits
|
||||
for (waddr, bitaddr), tile_desc in tile_used.items():
|
||||
used_desc = used.get((waddr, bitaddr), None)
|
||||
if used_desc:
|
||||
raise ValueError("Collision at %08X:%04X: had %s, got %s" % (waddr, bitaddr, used_desc, tile_desc))
|
||||
used[(waddr, bitaddr)] = tile_desc
|
||||
collisions = set(mall.keys()).intersection(set(mtile.keys()))
|
||||
if collisions:
|
||||
print("ERROR: %s collisions" % len(collisions))
|
||||
for ck in sorted(collisions):
|
||||
addr, bitaddr = ck
|
||||
print(
|
||||
" %08X_%04X: had %s, got %s" %
|
||||
(addr, bitaddr, mall[ck], mtile[ck]))
|
||||
raise ValueError("%s collisions" % len(collisions))
|
||||
mall.update(mtile)
|
||||
tiles_checked += 1
|
||||
print("Checked %s tiles, %s bits" % tiles_checked, len(used))
|
||||
print("Checked %s tiles, %s bits" % (tiles_checked, len(mall)))
|
||||
|
||||
|
||||
def run(db_root, verbose=False):
|
||||
def run(db_root, strict=False, verbose=False):
|
||||
# Start by running a basic check on db files
|
||||
print("Checking individual .db...")
|
||||
parsedb_all(db_root, verbose=verbose)
|
||||
|
||||
'''
|
||||
# Now load and verify tile consistency
|
||||
db = prjxraydb.Database(db_root)
|
||||
db._read_tilegrid()
|
||||
'''
|
||||
these don't load properly without .json files
|
||||
See: https://github.com/SymbiFlow/prjxray/issues/303
|
||||
db._read_tile_types()
|
||||
print(db.tile_types.keys())
|
||||
'''
|
||||
|
||||
check_seg_overlap(db_root, verbose=verbose)
|
||||
verbose and print("")
|
||||
|
||||
print("Checking aggregate dir...")
|
||||
check_tile_overlap(db, db_root, strict=strict, verbose=verbose)
|
||||
|
||||
|
||||
def main():
|
||||
|
|
@ -97,10 +118,11 @@ def main():
|
|||
description="Parse a db repository, checking for consistency")
|
||||
|
||||
util.db_root_arg(parser)
|
||||
parser.add_argument('--strict', action='store_true', help='')
|
||||
parser.add_argument('--verbose', action='store_true', help='')
|
||||
args = parser.parse_args()
|
||||
|
||||
run(args.db_root, verbose=args.verbose)
|
||||
run(args.db_root, strict=args.strict, verbose=args.verbose)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -46,22 +46,10 @@ def get_database(db, tile_type, verbose=False):
|
|||
parts = l.split()
|
||||
name = parts[0]
|
||||
|
||||
def parsetag(x):
|
||||
# !30_07
|
||||
if x[0] == '!':
|
||||
isset = False
|
||||
numstr = x[1:]
|
||||
else:
|
||||
isset = True
|
||||
numstr = x
|
||||
frame, word = numstr.split("_")
|
||||
# second part forms a tuple refereced in sets
|
||||
return (isset, (int(frame, 10), int(word, 10)))
|
||||
|
||||
if parts[1] == 'always' or parts[1] == 'hint':
|
||||
tagbits = []
|
||||
else:
|
||||
tagbits = [parsetag(x) for x in parts[1:]]
|
||||
tagbits = [util.parse_tagbit(x) for x in parts[1:]]
|
||||
|
||||
tags.append(list([name] + tagbits))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue