Run make format.

Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
Keith Rothman 2018-10-19 16:19:22 -07:00
parent b22001a645
commit e7370d6fdc
21 changed files with 170 additions and 136 deletions

View File

@ -13,9 +13,9 @@ f.write("i,prim,loc,bel,init\n")
def gen_slices():
for _tile_name, site_name, _site_type in util.get_roi().gen_sites([
'SLICEL',
'SLICEM',
]):
'SLICEL',
'SLICEM',
]):
yield site_name

View File

@ -7,10 +7,8 @@ print('//Requested CLBs: %s' % str(CLBN))
def gen_slices():
for _tile_name, site_name, _site_type in util.get_roi().gen_sites([
'SLICEL',
'SLICEM'
]):
for _tile_name, site_name, _site_type in util.get_roi().gen_sites(
['SLICEL', 'SLICEM']):
yield site_name

View File

@ -7,10 +7,8 @@ print('//Requested CLBs: %s' % str(CLBN))
def gen_slices():
for _tile_name, site_name, _site_type in util.get_roi().gen_sites([
'SLICEL',
'SLICEM'
]):
for _tile_name, site_name, _site_type in util.get_roi().gen_sites(
['SLICEL', 'SLICEM']):
yield site_name

View File

@ -8,9 +8,9 @@ print('//Requested CLBs: %s' % str(CLBN))
def gen_slices():
for _tile_name, site_name, _site_type in util.get_roi().gen_sites([
'SLICEL',
'SLICEM',
]):
'SLICEL',
'SLICEM',
]):
yield site_name

View File

@ -7,10 +7,8 @@ print('//Requested CLBs: %s' % str(CLBN))
def gen_slices():
for _tile_name, site_name, _site_type in util.get_roi().gen_sites([
'SLICEL',
'SLICEM'
]):
for _tile_name, site_name, _site_type in util.get_roi().gen_sites(
['SLICEL', 'SLICEM']):
yield site_name

View File

@ -24,7 +24,8 @@ print('//Requested CLBs: %s' % str(CLBN))
def gen_slicems():
for _tile_name, site_name, _site_type in util.get_roi().gen_sites(['SLICEM']):
for _tile_name, site_name, _site_type in util.get_roi().gen_sites(
['SLICEM']):
yield site_name

View File

@ -7,7 +7,8 @@ print('//Requested CLBs: %s' % str(CLBN))
def gen_slicems():
for _tile_name, site_name, _site_type in util.get_roi().gen_sites(['SLICEM']):
for _tile_name, site_name, _site_type in util.get_roi().gen_sites(
['SLICEM']):
yield site_name

View File

@ -1,6 +1,7 @@
# Break frames into WORD_SIZE bit words.
WORD_SIZE_BITS = 32
def load_bitdata(f):
""" Read bit file and return bitdata map.
@ -22,6 +23,6 @@ def load_bitdata(f):
bitdata[frame] = set(), set()
bitdata[frame][0].add(wordidx)
bitdata[frame][1].add(wordidx*WORD_SIZE_BITS + bitidx)
bitdata[frame][1].add(wordidx * WORD_SIZE_BITS + bitidx)
return bitdata

View File

@ -137,6 +137,6 @@ class Database(object):
def get_tile_segbits(self, tile_type):
if tile_type not in self.tile_segbits:
self.tile_segbits[tile_type] = tile_segbits.TileSegbits(
self.tile_types[tile_type.upper()])
self.tile_types[tile_type.upper()])
return self.tile_segbits[tile_type]

View File

@ -2,20 +2,25 @@ import fasm
from prjxray import bitstream
from prjxray import grid
class FasmLookupError(Exception):
pass
class FasmInconsistentBits(Exception):
pass
# How many 32-bit words for frame in a 7-series bitstream?
FRAME_WORD_COUNT = 101
def init_frame_at_address(frames, addr):
'''Set given frame to 0 if not initialized '''
if not addr in frames:
frames[addr] = [0 for _i in range(FRAME_WORD_COUNT)]
class FasmAssembler(object):
def __init__(self, db):
self.db = db
@ -44,7 +49,8 @@ class FasmAssembler(object):
for bits_info in self.grid.iter_all_frames():
for coli in range(bits_info.bits.frames):
init_frame_at_address(frames, bits_info.bits.base_address + coli)
init_frame_at_address(
frames, bits_info.bits.base_address + coli)
return frames
@ -56,8 +62,11 @@ class FasmAssembler(object):
if key in self.frames:
if self.frames[key] != 1:
raise FasmInconsistentBits(
'FASM line "{}" wanted to set bit {} but was cleared by FASM line "{}"'.format(
line, key, self.frames_line[key],
'FASM line "{}" wanted to set bit {} but was cleared by FASM line "{}"'
.format(
line,
key,
self.frames_line[key],
))
return
@ -72,8 +81,11 @@ class FasmAssembler(object):
if key in self.frames:
if self.frames[key] != 0:
raise FasmInconsistentBits(
'FASM line "{}" wanted to clear bit {} but was set by FASM line "{}"'.format(
line, key, self.frames_line[key],
'FASM line "{}" wanted to clear bit {} but was set by FASM line "{}"'
.format(
line,
key,
self.frames_line[key],
))
return

View File

@ -2,6 +2,7 @@ import re
import fasm
from prjxray import bitstream
def mk_fasm(tile_name, feature):
""" Convert matches tile and feature to FasmLine tuple. """
# Seperate addressing of multi-bit features:
@ -16,18 +17,20 @@ def mk_fasm(tile_name, feature):
feature = '{}.{}'.format(tile_name, tag_post)
return fasm.FasmLine(
set_feature=fasm.SetFasmFeature(
feature=feature,
start=address,
end=None,
value=1,
value_format=None,
),
annotations=None,
comment=None)
set_feature=fasm.SetFasmFeature(
feature=feature,
start=address,
end=None,
value=1,
value_format=None,
),
annotations=None,
comment=None)
class FasmDisassembler(object):
""" Given a Project X-ray data, outputs FasmLine tuples for bits set. """
def __init__(self, db):
self.db = db
self.grid = self.db.grid()
@ -47,26 +50,25 @@ class FasmDisassembler(object):
return
comment = " WARNING: failed to load DB for tile type {}".format(
gridinfo.tile_type)
gridinfo.tile_type)
yield fasm.FasmLine(
set_feature=None,
annotations=None,
comment=comment,
)
set_feature=None,
annotations=None,
comment=comment,
)
yield fasm.FasmLine(
set_feature=None,
annotations=[
fasm.Annotation('missing_segbits', gridinfo.tile_type),
fasm.Annotation('exception', str(e)),
],
comment=None,
)
set_feature=None,
annotations=[
fasm.Annotation('missing_segbits', gridinfo.tile_type),
fasm.Annotation('exception', str(e)),
],
comment=None,
)
self.decode_warnings.add(gridinfo.tile_type)
return
for ones_matched, feature in tile_segbits.match_bitdata(
bits, bitdata):
for ones_matched, feature in tile_segbits.match_bitdata(bits, bitdata):
for frame, bit in ones_matched:
bitdata[frame][1].remove(bit)
@ -102,9 +104,7 @@ class FasmDisassembler(object):
tiles_checked.add(bits_info.tile)
for fasm_line in self.find_features_in_tile(
bits_info.tile,
bits_info.bits,
bitdata,
bits_info.tile, bits_info.bits, bitdata,
verbose=verbose):
yield fasm_line
@ -112,19 +112,22 @@ class FasmDisassembler(object):
# Some bits were not decoded, add warning and annotations to
# FASM.
yield fasm.FasmLine(
set_feature=None,
annotations=None,
comment=" In frame 0x{:08x} {} bits were not converted.".format(
frame, len(bitdata[frame]),
))
set_feature=None,
annotations=None,
comment=" In frame 0x{:08x} {} bits were not converted.".
format(
frame,
len(bitdata[frame]),
))
for bit in bitdata[frame][1]:
wordidx = bit // bitstream.WORD_SIZE_BITS
bitidx = bit % bitstream.WORD_SIZE_BITS
annotation = fasm.Annotation('unknown_bit',
'{:08x}_{}_{}'.format(frame, wordidx, bitidx))
annotation = fasm.Annotation(
'unknown_bit', '{:08x}_{}_{}'.format(
frame, wordidx, bitidx))
yield fasm.FasmLine(
set_feature=None,
annotations=[annotation],
comment=None,
)
set_feature=None,
annotations=[annotation],
comment=None,
)

View File

@ -2,6 +2,7 @@ from collections import namedtuple
import enum
from prjxray import segment_map
class SegmentType(enum.Enum):
# Segments describing CLB features, interconnect, clocks and IOs.
CLB_IO_CLK = 'CLB_IO_CLK'
@ -9,11 +10,13 @@ class SegmentType(enum.Enum):
# Segments describing block RAM initialization.
BLOCK_RAM = 'BLOCK_RAM'
GridLoc = namedtuple('GridLoc', 'grid_x grid_y')
GridInfo = namedtuple('GridInfo', 'segment bits sites tile_type in_roi')
Bits = namedtuple('Bits', 'base_address frames offset words')
BitsInfo = namedtuple('BitsInfo', 'segment_type tile bits')
class Grid(object):
""" Object that represents grid for a given database.
@ -62,7 +65,7 @@ class Grid(object):
frames=tileinfo['bits'][k]['frames'],
offset=tileinfo['bits'][k]['offset'],
words=tileinfo['bits'][k]['words'],
)
)
self.tileinfo[tile] = GridInfo(
segment=tileinfo['segment'] if 'segment' in tileinfo else None,
@ -107,10 +110,10 @@ class Grid(object):
for tile, tileinfo in self.tileinfo.items():
for segment_type, bits in tileinfo.bits.items():
yield BitsInfo(
segment_type=segment_type,
tile=tile,
bits=bits,
)
segment_type=segment_type,
tile=tile,
bits=bits,
)
def get_segment_map(self):
return segment_map.SegmentMap(self)

View File

@ -1,5 +1,6 @@
import json
class Roi(object):
def __init__(self, tilegrid_file, x1, x2, y1, y2):
self.tilegrid_file = tilegrid_file
@ -12,14 +13,13 @@ class Roi(object):
def tile_in_roi(self, tilej):
x = int(tilej['grid_x'])
y = int(tilej['grid_y'])
return self.x1 <= x and x <= self.x2 and self.y1 <= y and y <= self.y2
return self.x1 <= x and x <= self.x2 and self.y1 <= y and y <= self.y2
def read_tilegrid(self):
if not self.tilegrid:
with open(self.tilegrid_file) as f:
self.tilegrid = json.load(f)
def gen_tiles(self, tile_types=None):
'''
tile_types: list of tile types to keep, or None for all
@ -29,10 +29,9 @@ class Roi(object):
for tile_name, tilej in self.tilegrid.items():
if self.tile_in_roi(tilej) and (tile_types is None
or tilej['type'] in tile_types):
or tilej['type'] in tile_types):
yield (tile_name, tilej)
def gen_sites(self, site_types=None):
'''
site_types: list of site types to keep, or None for all

View File

@ -1,15 +1,17 @@
from intervaltree import IntervalTree, Interval
from prjxray import bitstream
class SegmentMap(object):
def __init__(self, grid):
self.segment_tree = IntervalTree()
for bits_info in grid.iter_all_frames():
self.segment_tree.add(Interval(
begin=bits_info.bits.base_address,
end=bits_info.bits.base_address+bits_info.bits.frames,
data=bits_info,
self.segment_tree.add(
Interval(
begin=bits_info.bits.base_address,
end=bits_info.bits.base_address + bits_info.bits.frames,
data=bits_info,
))
def segment_info_for_frame(self, frame):

View File

@ -1,7 +1,6 @@
from collections import namedtuple
import json
from prjxray import lib
""" Database files available for a tile """
TileDbs = namedtuple('TileDbs', 'segbits ppips mask tile_type')

View File

@ -2,11 +2,13 @@ from collections import namedtuple
from prjxray import bitstream
import enum
class PsuedoPipType(enum.Enum):
ALWAYS = 'always'
DEFAULT = 'default'
HINT = 'hint'
def read_ppips(f):
ppips = {}
@ -21,8 +23,10 @@ def read_ppips(f):
return ppips
Bit = namedtuple('Bit', 'word_column word_bit isset')
def parsebit(val):
'''Return "!012_23" => (12, 23, False)'''
isset = True
@ -34,10 +38,11 @@ def parsebit(val):
seg_word_column, word_bit_n = val.split('_')
return Bit(
word_column=int(seg_word_column),
word_bit=int(word_bit_n),
isset=isset,
)
word_column=int(seg_word_column),
word_bit=int(word_bit_n),
isset=isset,
)
def read_segbits(f):
segbits = {}
@ -57,6 +62,7 @@ def read_segbits(f):
return segbits
class TileSegbits(object):
def __init__(self, tile_db):
self.segbits = {}
@ -65,7 +71,7 @@ class TileSegbits(object):
if tile_db.ppips is not None:
with open(tile_db.ppips) as f:
self.ppips = read_ppips(f)
self.ppips = read_ppips(f)
if tile_db.segbits is not None:
with open(tile_db.segbits) as f:
@ -83,8 +89,8 @@ class TileSegbits(object):
if base_feature not in self.feature_addresses:
self.feature_addresses[base_feature] = {}
self.feature_addresses[base_feature][int(feature[sidx+1:eidx])] = feature
self.feature_addresses[base_feature][int(
feature[sidx + 1:eidx])] = feature
def match_bitdata(self, bits, bitdata):
""" Return matching features for tile bits data (grid.Bits) and bitdata.
@ -96,8 +102,8 @@ class TileSegbits(object):
for feature, segbit in self.segbits.items():
match = True
for query_bit in segbit:
frame = bits.base_address + query_bit.word_column
bitidx = bits.offset*bitstream.WORD_SIZE_BITS + query_bit.word_bit
frame = bits.base_address + query_bit.word_column
bitidx = bits.offset * bitstream.WORD_SIZE_BITS + query_bit.word_bit
if frame not in bitdata:
match = not query_bit.isset
@ -118,8 +124,8 @@ class TileSegbits(object):
def inner():
for query_bit in segbit:
if query_bit.isset:
frame = bits.base_address + query_bit.word_column
bitidx = bits.offset*bitstream.WORD_SIZE_BITS + query_bit.word_bit
frame = bits.base_address + query_bit.word_column
bitidx = bits.offset * bitstream.WORD_SIZE_BITS + query_bit.word_bit
yield (frame, bitidx)
yield (tuple(inner()), feature)

View File

@ -2,10 +2,12 @@ import os
import re
from .roi import Roi
def get_db_root():
return "%s/%s" % (
os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"))
def roi_xy():
x1 = int(os.getenv('XRAY_ROI_GRID_X1'))
x2 = int(os.getenv('XRAY_ROI_GRID_X2'))
@ -14,6 +16,7 @@ def roi_xy():
return (x1, x2), (y1, y2)
def slice_xy():
'''Return (X1, X2), (Y1, Y2) from XRAY_ROI, exclusive end (for xrange)'''
# SLICE_X12Y100:SLICE_X27Y149
@ -24,14 +27,16 @@ def slice_xy():
ms = [int(m.group(i + 1)) for i in range(4)]
return ((ms[0], ms[2] + 1), (ms[1], ms[3] + 1))
def get_roi():
(x1, x2), (y1, y2) = roi_xy()
return Roi(
tilegrid_file=os.path.join(get_db_root(), 'tilegrid.json'),
x1=x1,
x2=x2,
y1=y1,
y2=y2)
tilegrid_file=os.path.join(get_db_root(), 'tilegrid.json'),
x1=x1,
x2=x2,
y1=y1,
y2=y2)
# we know that all bits for CLB MUXes are in frames 30 and 31, so filter all other bits
def bitfilter_clb_mux(frame_idx, bit_idx):

View File

@ -9,15 +9,18 @@ from prjxray import db
from prjxray import fasm_disassembler
from prjxray import bitstream
def run(db_root, bits_file, verbose, canonical):
disassembler = fasm_disassembler.FasmDisassembler(db.Database(db_root))
with open(bits_file) as f:
bitdata = bitstream.load_bitdata(f)
print(fasm.fasm_tuple_to_string(
disassembler.find_features_in_bitstream(bitdata, verbose=verbose),
canonical=canonical))
print(
fasm.fasm_tuple_to_string(
disassembler.find_features_in_bitstream(bitdata, verbose=verbose),
canonical=canonical))
def main():
import argparse
@ -34,16 +37,18 @@ def main():
db_root_kwargs['required'] = False
db_root_kwargs['default'] = os.path.join(database_dir, database)
parser.add_argument(
'--db_root', help="Database root.", **db_root_kwargs)
parser.add_argument('--db_root', help="Database root.", **db_root_kwargs)
parser.add_argument('bits_file', help='')
parser.add_argument('verbose', help='Print lines for unknown tiles and bits',
action='store_true')
parser.add_argument('--canonical', help='Output canonical bitstream.',
action='store_true')
parser.add_argument(
'verbose',
help='Print lines for unknown tiles and bits',
action='store_true')
parser.add_argument(
'--canonical', help='Output canonical bitstream.', action='store_true')
args = parser.parse_args()
run(args.db_root, args.bits_file, args.verbose, args.canonical)
if __name__ == '__main__':
main()

View File

@ -7,6 +7,7 @@ import os
import fasm
from prjxray import db
def process_fasm(db_root, fasm_file, canonical):
database = db.Database(db_root)
grid = database.grid()
@ -20,7 +21,6 @@ def process_fasm(db_root, fasm_file, canonical):
parts = feature.feature.split('.')
tile = parts[0]
gridinfo = grid.gridinfo_at_tilename(tile)
tile_segbits = database.get_tile_segbits(gridinfo.tile_type)
@ -28,21 +28,23 @@ def process_fasm(db_root, fasm_file, canonical):
if feature.start is not None:
address = feature.start
feature_name = '{}.{}'.format(gridinfo.tile_type, '.'.join(parts[1:]))
feature_name = '{}.{}'.format(
gridinfo.tile_type, '.'.join(parts[1:]))
# Convert feature to bits. If no bits are set, feature is
# psuedo pip, and should not be output from canonical FASM.
bits = tuple(tile_segbits.feature_to_bits(feature_name, address=address))
bits = tuple(
tile_segbits.feature_to_bits(feature_name, address=address))
if len(bits) == 0 and canonical:
continue
# In canonical output, only output the canonical features.
if canonical:
yield fasm.FasmLine(
set_feature=feature,
annotations=None,
comment=None,
)
set_feature=feature,
annotations=None,
comment=None,
)
# If not in canonical mode, output original FASM line
if not canonical:
@ -50,15 +52,18 @@ def process_fasm(db_root, fasm_file, canonical):
def run(db_root, fasm_file, canonical):
print(fasm.fasm_tuple_to_string(
process_fasm(db_root, fasm_file, canonical),
canonical=canonical))
print(
fasm.fasm_tuple_to_string(
process_fasm(db_root, fasm_file, canonical), canonical=canonical))
def main():
import argparse
parser = argparse.ArgumentParser(
description='Read FASM file, check against database, and output optionally canonical FASM.')
description=
'Read FASM file, check against database, and output optionally canonical FASM.'
)
database_dir = os.getenv("XRAY_DATABASE_DIR")
database = os.getenv("XRAY_DATABASE")
@ -69,15 +74,14 @@ def main():
db_root_kwargs['required'] = False
db_root_kwargs['default'] = os.path.join(database_dir, database)
parser.add_argument(
'--db_root', help="Database root.", **db_root_kwargs)
parser.add_argument('--db_root', help="Database root.", **db_root_kwargs)
parser.add_argument('fasm_file', help='Input FASM file')
parser.add_argument('--canonical', help='Output canonical bitstream.',
action='store_true')
parser.add_argument(
'--canonical', help='Output canonical bitstream.', action='store_true')
args = parser.parse_args()
run(args.db_root, args.fasm_file, args.canonical)
if __name__ == '__main__':
main()

View File

@ -7,6 +7,7 @@ import argparse
import os
import os.path
def dump_frames_verbose(frames):
print()
print("Frames: %d" % len(frames))
@ -16,6 +17,7 @@ def dump_frames_verbose(frames):
'0x%08X ' % addr + ', '.join(['0x%08X' % w for w in words]) +
'...')
def dump_frames_sparse(frames):
print()
print("Frames: %d" % len(frames))
@ -34,6 +36,7 @@ def dump_frames_sparse(frames):
if w:
print(' % 3d: 0x%08X' % (i, w))
def dump_frm(f, frames):
'''Write a .frm file given a list of frames, each containing a list of 101 32 bit words'''
for addr in sorted(frames.keys()):
@ -41,6 +44,7 @@ def dump_frm(f, frames):
f.write(
'0x%08X ' % addr + ','.join(['0x%08X' % w for w in words]) + '\n')
def run(db_root, filename_in, f_out, sparse=False, debug=False):
assembler = fasm_assembler.FasmAssembler(db.Database(db_root))
assembler.parse_fasm_filename(filename_in)
@ -67,15 +71,12 @@ def main():
db_root_kwargs['required'] = False
db_root_kwargs['default'] = os.path.join(database_dir, database)
parser.add_argument(
'--db_root', help="Database root.", **db_root_kwargs)
parser.add_argument('--db_root', help="Database root.", **db_root_kwargs)
parser.add_argument(
'--sparse', action='store_true', help="Don't zero fill all frames")
parser.add_argument(
'--debug', action='store_true', help="Print debug dump")
parser.add_argument(
'fn_in',
help='Input FPGA assembly (.fasm) file')
parser.add_argument('fn_in', help='Input FPGA assembly (.fasm) file')
parser.add_argument(
'fn_out',
default='/dev/stdout',
@ -88,8 +89,8 @@ def main():
filename_in=args.fn_in,
f_out=open(args.fn_out, 'w'),
sparse=args.sparse,
debug=args.debug
)
debug=args.debug)
if __name__ == '__main__':
main()

View File

@ -5,13 +5,11 @@ import os.path
import fasm
from prjxray import db
def main():
import argparse
parser = argparse.ArgumentParser(
description=
'Convert FASM to pip list'
)
parser = argparse.ArgumentParser(description='Convert FASM to pip list')
database_dir = os.getenv("XRAY_DATABASE_DIR")
database = os.getenv("XRAY_DATABASE")
@ -22,11 +20,8 @@ def main():
db_root_kwargs['required'] = False
db_root_kwargs['default'] = os.path.join(database_dir, database)
parser.add_argument(
'--db_root', help="Database root.", **db_root_kwargs)
parser.add_argument(
'fn_in',
help='Input FPGA assembly (.fasm) file')
parser.add_argument('--db_root', help="Database root.", **db_root_kwargs)
parser.add_argument('fn_in', help='Input FPGA assembly (.fasm) file')
args = parser.parse_args()
database = db.Database(args.db_root)
@ -47,7 +42,10 @@ def main():
if pip.net_from == parts[2] and pip.net_to == parts[1]:
yield '{}/{}.{}'.format(tile, gridinfo.tile_type, pip.name)
print('highlight_objects [concat {}]'.format(' '.join('[get_pips {}]'.format(pip) for pip in inner())))
print(
'highlight_objects [concat {}]'.format(
' '.join('[get_pips {}]'.format(pip) for pip in inner())))
if __name__ == '__main__':
main()