| from collections import namedtuple | |
| from utils import bitstream | |
| from utils.grid import BlockType | |
| import enum | |
| import functools | |
| 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 | |
| seg_word_column, word_bit_n = val.split('_') | |
| 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 | |
| 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 open(tile_db.ppips) as f: | |
| self.ppips = read_ppips(f) | |
| if tile_db.segbits is not None: | |
| with open(tile_db.segbits) as f: | |
| self.segbits[BlockType.CLB_IO_CLK] = read_segbits(f) | |
| if tile_db.block_ram_segbits is not None: | |
| with open(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) |