mirror of https://github.com/openXC7/prjxray.git
184 lines
5.2 KiB
Python
184 lines
5.2 KiB
Python
#!/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
|
|
from collections import namedtuple
|
|
from prjxray import bitstream
|
|
from prjxray.grid_types import BlockType
|
|
from prjxray.util import OpenSafeFile
|
|
import enum
|
|
|
|
|
|
class PsuedoPipType(enum.Enum):
|
|
ALWAYS = 'always'
|
|
DEFAULT = 'default'
|
|
HINT = 'hint'
|
|
|
|
|
|
def read_ppips(f):
|
|
ppips = {}
|
|
|
|
for l in f:
|
|
l = l.strip()
|
|
if not l:
|
|
continue
|
|
|
|
feature, ppip_type = l.split(' ')
|
|
|
|
ppips[feature] = PsuedoPipType(ppip_type)
|
|
|
|
return ppips
|
|
|
|
|
|
Bit = namedtuple('Bit', 'word_column word_bit isset')
|
|
|
|
|
|
def parsebit(val):
|
|
'''Return "!012_23" => (12, 23, False)'''
|
|
isset = True
|
|
# Default is 0. Skip explicit call outs
|
|
if val[0] == '!':
|
|
isset = False
|
|
val = val[1:]
|
|
# 28_05 => 28, 05
|
|
parts = val.split('_')
|
|
assert len(parts) == 2, val
|
|
seg_word_column, word_bit_n = parts
|
|
|
|
return Bit(
|
|
word_column=int(seg_word_column),
|
|
word_bit=int(word_bit_n),
|
|
isset=isset,
|
|
)
|
|
|
|
|
|
def read_segbits(f):
|
|
segbits = {}
|
|
|
|
for l in f:
|
|
# CLBLM_L.SLICEL_X1.ALUT.INIT[10] 29_14
|
|
l = l.strip()
|
|
|
|
if not l:
|
|
continue
|
|
|
|
parts = l.split(' ')
|
|
|
|
assert len(parts) > 1, l
|
|
|
|
segbits[parts[0]] = [parsebit(val) for val in parts[1:]]
|
|
|
|
return segbits
|
|
|
|
|
|
class TileSegbits(object):
|
|
def __init__(self, tile_db):
|
|
self.segbits = {}
|
|
self.ppips = {}
|
|
self.feature_addresses = {}
|
|
|
|
if tile_db.ppips is not None:
|
|
with OpenSafeFile(tile_db.ppips) as f:
|
|
self.ppips = read_ppips(f)
|
|
|
|
if tile_db.segbits is not None:
|
|
with OpenSafeFile(tile_db.segbits) as f:
|
|
self.segbits[BlockType.CLB_IO_CLK] = read_segbits(f)
|
|
|
|
if tile_db.block_ram_segbits is not None:
|
|
with OpenSafeFile(tile_db.block_ram_segbits) as f:
|
|
self.segbits[BlockType.BLOCK_RAM] = read_segbits(f)
|
|
|
|
for block_type in self.segbits:
|
|
for feature in self.segbits[block_type]:
|
|
sidx = feature.rfind('[')
|
|
eidx = feature.rfind(']')
|
|
|
|
if sidx != -1:
|
|
assert eidx != -1
|
|
|
|
base_feature = feature[:sidx]
|
|
|
|
if base_feature not in self.feature_addresses:
|
|
self.feature_addresses[base_feature] = {}
|
|
|
|
self.feature_addresses[base_feature][int(
|
|
feature[sidx + 1:eidx])] = (block_type, feature)
|
|
|
|
def match_bitdata(self, block_type, bits, bitdata, match_filter=None):
|
|
""" Return matching features for tile bits data (grid.Bits) and bitdata.
|
|
|
|
See bitstream.load_bitdata for details on bitdata structure.
|
|
|
|
"""
|
|
|
|
if block_type not in self.segbits:
|
|
return
|
|
|
|
for feature, segbit in self.segbits[block_type].items():
|
|
match = True
|
|
skip = False
|
|
for query_bit in segbit:
|
|
if match_filter is not None and not match_filter(block_type,
|
|
query_bit):
|
|
skip = True
|
|
break
|
|
|
|
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
|
|
if match:
|
|
continue
|
|
else:
|
|
break
|
|
|
|
found_bit = bitidx in bitdata[frame][1]
|
|
match = found_bit == query_bit.isset
|
|
|
|
if not match:
|
|
break
|
|
|
|
if not match or skip:
|
|
continue
|
|
|
|
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
|
|
yield (frame, bitidx)
|
|
|
|
yield (tuple(inner()), feature)
|
|
|
|
def map_bit_to_frame(self, block_type, bits, bit):
|
|
""" Convert bit from segbit to frame data. """
|
|
return Bit(
|
|
word_column=bits.base_address + bit.word_column,
|
|
word_bit=bits.offset * bitstream.WORD_SIZE_BITS + bit.word_bit,
|
|
isset=bit.isset,
|
|
)
|
|
|
|
def feature_to_bits(self, bits_map, feature, address=0):
|
|
if feature in self.ppips:
|
|
return
|
|
|
|
for block_type in self.segbits:
|
|
if address == 0 and feature in self.segbits[block_type]:
|
|
for bit in self.segbits[block_type][feature]:
|
|
yield block_type, self.map_bit_to_frame(
|
|
block_type, bits_map[block_type], bit)
|
|
return
|
|
|
|
block_type, feature = self.feature_addresses[feature][address]
|
|
for bit in self.segbits[block_type][feature]:
|
|
yield block_type, self.map_bit_to_frame(
|
|
block_type, bits_map[block_type], bit)
|