checkdb: check tile overlap

Signed-off-by: John McMaster <johndmcmaster@gmail.com>
This commit is contained in:
John McMaster 2018-12-10 14:42:53 -08:00
parent 5060dae1be
commit 96ee4ac449
3 changed files with 124 additions and 60 deletions

View File

@ -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)

View File

@ -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__':

View File

@ -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))