2018-12-10 20:22:40 +01:00
|
|
|
#!/usr/bin/env python3
|
2020-04-16 09:29:20 +02:00
|
|
|
# -*- 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
|
2018-12-10 20:22:40 +01:00
|
|
|
'''
|
|
|
|
|
Check:
|
|
|
|
|
-Individual files are valid
|
|
|
|
|
-No overlap between any tile
|
2018-12-10 23:42:53 +01:00
|
|
|
|
|
|
|
|
TODO:
|
|
|
|
|
Can we use prjxray?
|
|
|
|
|
Relies on 074, which is too far into the process
|
2018-12-10 20:22:40 +01:00
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
from prjxray import util
|
2018-12-10 23:42:53 +01:00
|
|
|
from prjxray import db as prjxraydb
|
|
|
|
|
import os
|
2020-05-21 16:32:49 +02:00
|
|
|
import utils.parsedb as parsedb
|
2018-12-10 20:22:40 +01:00
|
|
|
#from prjxray import db as prjxraydb
|
|
|
|
|
import glob
|
2019-02-11 17:17:28 +01:00
|
|
|
|
2018-12-10 20:22:40 +01:00
|
|
|
|
2019-02-12 18:50:08 +01:00
|
|
|
def gen_tile_bits(tile_segbits, tile_bits):
|
2019-02-12 17:00:16 +01:00
|
|
|
'''
|
|
|
|
|
For given tile and corresponding db_file structure yield
|
|
|
|
|
(absolute address, absolute FDRI bit offset, tag)
|
|
|
|
|
|
|
|
|
|
For each tag bit in the corresponding block_type entry, calculate absolute address and bit offsets
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
for block_type in tile_segbits:
|
|
|
|
|
assert block_type in tile_bits, "block type %s is not present in current tile" % block_type
|
|
|
|
|
|
|
|
|
|
block = tile_bits[block_type]
|
|
|
|
|
|
|
|
|
|
baseaddr = block.base_address
|
|
|
|
|
bitbase = 32 * block.offset
|
|
|
|
|
frames = block.frames
|
|
|
|
|
|
|
|
|
|
for tag in tile_segbits[block_type]:
|
|
|
|
|
for bit in tile_segbits[block_type][tag]:
|
|
|
|
|
# 31_06
|
|
|
|
|
word_column = bit.word_column
|
|
|
|
|
word_bit = bit.word_bit
|
|
|
|
|
assert word_column <= frames, "ERROR: bit out of bound --> tag: %s; word_column = %s; frames = %s" % (
|
|
|
|
|
tag, word_column, frames)
|
|
|
|
|
yield word_column + baseaddr, word_bit + bitbase, tag
|
|
|
|
|
|
|
|
|
|
|
2019-02-12 18:50:08 +01:00
|
|
|
def make_tile_mask(tile_segbits, tile_name, tile_bits):
|
2018-12-10 23:42:53 +01:00
|
|
|
'''
|
|
|
|
|
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()
|
2019-02-12 18:50:08 +01:00
|
|
|
for absaddr, bitaddr, tag in gen_tile_bits(tile_segbits, tile_bits):
|
2018-12-10 23:42:53 +01:00
|
|
|
name = "%s.%s" % (tile_name, tag)
|
|
|
|
|
ret.setdefault((absaddr, bitaddr), name)
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
2018-12-10 20:22:40 +01:00
|
|
|
def parsedb_all(db_root, verbose=False):
|
|
|
|
|
'''Verify .db files are individually valid'''
|
|
|
|
|
|
2018-12-10 23:42:53 +01:00
|
|
|
files = 0
|
|
|
|
|
for bit_fn in glob.glob('%s/segbits_*.db' % db_root):
|
2019-05-27 08:45:15 +02:00
|
|
|
# Don't parse db files with fuzzer origin information
|
|
|
|
|
if "origin_info" in bit_fn:
|
|
|
|
|
continue
|
2018-12-10 23:42:53 +01:00
|
|
|
verbose and print("Checking %s" % bit_fn)
|
2018-12-10 20:22:40 +01:00
|
|
|
parsedb.run(bit_fn, fnout=None, strict=True, verbose=verbose)
|
2018-12-10 23:42:53 +01:00
|
|
|
files += 1
|
|
|
|
|
print("segbits_*.db: %d okay" % files)
|
2018-12-10 20:22:40 +01:00
|
|
|
|
2018-12-10 23:42:53 +01:00
|
|
|
files = 0
|
|
|
|
|
for bit_fn in glob.glob('%s/mask_*.db' % db_root):
|
|
|
|
|
verbose and print("Checking %s" % bit_fn)
|
2018-12-10 20:22:40 +01:00
|
|
|
parsedb.run(bit_fn, fnout=None, strict=True, verbose=verbose)
|
2018-12-10 23:42:53 +01:00
|
|
|
files += 1
|
|
|
|
|
print("mask_*.db: %d okay" % files)
|
2018-12-10 20:22:40 +01:00
|
|
|
|
|
|
|
|
|
2019-02-12 18:50:08 +01:00
|
|
|
def check_tile_overlap(db, verbose=False):
|
2018-12-10 20:22:40 +01:00
|
|
|
'''
|
2018-12-10 23:42:53 +01:00
|
|
|
Verifies that no two tiles use the same bit
|
|
|
|
|
|
2018-12-10 20:22:40 +01:00
|
|
|
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
|
|
|
|
|
'''
|
2018-12-10 23:42:53 +01:00
|
|
|
mall = dict()
|
2019-02-12 14:02:42 +01:00
|
|
|
tiles_type_done = dict()
|
|
|
|
|
tile_segbits = dict()
|
2019-02-12 17:00:16 +01:00
|
|
|
grid = db.grid()
|
2018-12-10 20:22:40 +01:00
|
|
|
tiles_checked = 0
|
2018-12-10 23:54:40 +01:00
|
|
|
|
2019-02-12 17:00:16 +01:00
|
|
|
for tile_name in grid.tiles():
|
|
|
|
|
tile_info = grid.gridinfo_at_tilename(tile_name)
|
|
|
|
|
tile_type = tile_info.tile_type
|
|
|
|
|
tile_bits = tile_info.bits
|
2018-12-10 23:54:40 +01:00
|
|
|
|
2019-02-11 14:18:27 +01:00
|
|
|
if tile_type not in tiles_type_done:
|
2019-02-12 14:02:42 +01:00
|
|
|
segbits = db.get_tile_segbits(tile_type).segbits
|
|
|
|
|
tile_segbits[tile_type] = segbits
|
|
|
|
|
|
|
|
|
|
# If segbits has zero length the tile_type is marked True in order to be skipped
|
|
|
|
|
if len(segbits) == 0:
|
|
|
|
|
tiles_type_done[tile_type] = True
|
|
|
|
|
else:
|
|
|
|
|
tiles_type_done[tile_type] = False
|
2019-02-11 14:18:27 +01:00
|
|
|
|
2019-02-12 14:02:42 +01:00
|
|
|
if tiles_type_done[tile_type]:
|
|
|
|
|
continue
|
|
|
|
|
|
2019-02-12 18:50:08 +01:00
|
|
|
mtile = make_tile_mask(tile_segbits[tile_type], tile_name, tile_bits)
|
2018-12-10 23:42:53 +01:00
|
|
|
verbose and print(
|
|
|
|
|
"Checking %s, type %s, bits: %s" %
|
2019-02-12 18:50:08 +01:00
|
|
|
(tile_name, tile_type, len(mtile)))
|
2018-12-10 23:42:53 +01:00
|
|
|
if len(mtile) == 0:
|
2018-12-10 20:22:40 +01:00
|
|
|
continue
|
2018-12-10 23:42:53 +01:00
|
|
|
|
2019-02-12 14:02:42 +01:00
|
|
|
collisions = set()
|
|
|
|
|
for bits in mtile.keys():
|
2019-02-12 22:05:11 +01:00
|
|
|
if bits in mall.keys():
|
2019-02-12 14:02:42 +01:00
|
|
|
collisions.add(bits)
|
|
|
|
|
|
2018-12-10 23:42:53 +01:00
|
|
|
if collisions:
|
|
|
|
|
print("ERROR: %s collisions" % len(collisions))
|
|
|
|
|
for ck in sorted(collisions):
|
|
|
|
|
addr, bitaddr = ck
|
2018-12-10 23:54:40 +01:00
|
|
|
word, bit = util.addr_bit2word(bitaddr)
|
2018-12-10 23:42:53 +01:00
|
|
|
print(
|
2019-02-12 22:08:43 +01:00
|
|
|
" %s: had %s, got %s" %
|
|
|
|
|
(util.addr2str(addr, word, bit), mall[ck], mtile[ck]))
|
2018-12-10 23:42:53 +01:00
|
|
|
raise ValueError("%s collisions" % len(collisions))
|
2019-02-12 22:05:11 +01:00
|
|
|
mall.update(mtile)
|
2018-12-10 20:22:40 +01:00
|
|
|
tiles_checked += 1
|
2018-12-10 23:42:53 +01:00
|
|
|
print("Checked %s tiles, %s bits" % (tiles_checked, len(mall)))
|
2018-12-10 20:22:40 +01:00
|
|
|
|
|
|
|
|
|
2020-01-15 16:55:12 +01:00
|
|
|
def run(db_root, part, verbose=False):
|
2018-12-10 20:22:40 +01:00
|
|
|
# Start by running a basic check on db files
|
2018-12-10 23:42:53 +01:00
|
|
|
print("Checking individual .db...")
|
2018-12-10 20:22:40 +01:00
|
|
|
parsedb_all(db_root, verbose=verbose)
|
|
|
|
|
|
|
|
|
|
# Now load and verify tile consistency
|
2020-01-15 16:55:12 +01:00
|
|
|
db = prjxraydb.Database(db_root, part)
|
2018-12-10 20:22:40 +01:00
|
|
|
db._read_tilegrid()
|
2018-12-10 23:42:53 +01:00
|
|
|
'''
|
|
|
|
|
these don't load properly without .json files
|
|
|
|
|
See: https://github.com/SymbiFlow/prjxray/issues/303
|
2018-12-10 20:22:40 +01:00
|
|
|
db._read_tile_types()
|
|
|
|
|
print(db.tile_types.keys())
|
|
|
|
|
'''
|
|
|
|
|
|
2018-12-10 23:42:53 +01:00
|
|
|
verbose and print("")
|
|
|
|
|
|
|
|
|
|
print("Checking aggregate dir...")
|
2019-02-12 18:50:08 +01:00
|
|
|
check_tile_overlap(db, verbose=verbose)
|
2018-12-10 20:22:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
import argparse
|
|
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
|
description="Parse a db repository, checking for consistency")
|
|
|
|
|
|
|
|
|
|
util.db_root_arg(parser)
|
2020-01-17 15:58:24 +01:00
|
|
|
util.part_arg(parser)
|
2018-12-10 20:22:40 +01:00
|
|
|
parser.add_argument('--verbose', action='store_true', help='')
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
2020-01-17 15:58:24 +01:00
|
|
|
run(args.db_root, args.part, verbose=args.verbose)
|
2018-12-10 20:22:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
main()
|