mirror of https://github.com/openXC7/prjxray.git
IOB_SING solution via segbit aliases.
Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
This commit is contained in:
parent
ca45656e5f
commit
1307e11397
|
|
@ -245,6 +245,78 @@ def propagate_rebuf(database, tiles_by_grid):
|
|||
database[rebuf_above]['bits']['CLB_IO_CLK']['words'] = 4
|
||||
|
||||
|
||||
def propagate_IOB_SING(database, tiles_by_grid):
|
||||
""" The IOB_SING are half tiles at top and bottom of every IO column.
|
||||
|
||||
Unlike most tiles, they do not behave consistently. The tile at the top
|
||||
of the column is the bottom half of a full IOB, and the tile at the bottom
|
||||
of the column is the top half of a full IOB. For this reason, explicit
|
||||
bit aliasing is used to map the full IOB bits into the two halves, and a
|
||||
mapping is provided for the site naming.
|
||||
|
||||
"""
|
||||
|
||||
seen_iobs = set()
|
||||
for tile in database:
|
||||
if tile in seen_iobs:
|
||||
continue
|
||||
|
||||
if database[tile]["type"] not in ["LIOB33", "RIOB33"]:
|
||||
continue
|
||||
|
||||
while True:
|
||||
prev_tile = tile
|
||||
tile = tiles_by_grid[(
|
||||
database[tile]['grid_x'], database[tile]['grid_y'] + 1)]
|
||||
if '_SING' in database[tile]['type']:
|
||||
break
|
||||
|
||||
bottom_tile = tile
|
||||
seen_iobs.add(bottom_tile)
|
||||
|
||||
bits = database[prev_tile]['bits']['CLB_IO_CLK']
|
||||
|
||||
while True:
|
||||
tile = tiles_by_grid[(
|
||||
database[tile]['grid_x'], database[tile]['grid_y'] - 1)]
|
||||
seen_iobs.add(tile)
|
||||
|
||||
if '_SING' in database[tile]['type']:
|
||||
break
|
||||
|
||||
if 'CLB_IO_CLK' in database[tile]['bits']:
|
||||
assert bits['baseaddr'] == database[tile]['bits'][
|
||||
'CLB_IO_CLK']['baseaddr']
|
||||
assert bits['frames'] == database[tile]['bits']['CLB_IO_CLK'][
|
||||
'frames']
|
||||
assert bits['words'] == database[tile]['bits']['CLB_IO_CLK'][
|
||||
'words']
|
||||
|
||||
top_tile = tile
|
||||
|
||||
database[top_tile]['bits']['CLB_IO_CLK'] = copy.deepcopy(bits)
|
||||
database[top_tile]['bits']['CLB_IO_CLK']['words'] = 2
|
||||
database[top_tile]['bits']['CLB_IO_CLK']['offset'] = 99
|
||||
database[top_tile]['bits']['CLB_IO_CLK']['alias'] = {
|
||||
'type': database[prev_tile]['type'],
|
||||
'start_offset': 0,
|
||||
'sites': {
|
||||
'IOB33_Y0': 'IOB33_Y1',
|
||||
}
|
||||
}
|
||||
|
||||
database[bottom_tile]['bits']['CLB_IO_CLK'] = copy.deepcopy(bits)
|
||||
database[bottom_tile]['bits']['CLB_IO_CLK']['words'] = 2
|
||||
database[bottom_tile]['bits']['CLB_IO_CLK']['offset'] = 0
|
||||
database[bottom_tile]['bits']['CLB_IO_CLK']['alias'] = {
|
||||
'type': database[prev_tile]['type'],
|
||||
'start_offset': 2,
|
||||
'sites': {
|
||||
'IOB33_Y0': 'IOB33_Y0',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def run(json_in_fn, json_out_fn, verbose=False):
|
||||
# Load input files
|
||||
database = json.load(open(json_in_fn, "r"))
|
||||
|
|
@ -253,6 +325,7 @@ def run(json_in_fn, json_out_fn, verbose=False):
|
|||
propagate_INT_lr_bits(database, tiles_by_grid, verbose=verbose)
|
||||
propagate_INT_bits_in_column(database, tiles_by_grid)
|
||||
propagate_rebuf(database, tiles_by_grid)
|
||||
propagate_IOB_SING(database, tiles_by_grid)
|
||||
|
||||
# Save
|
||||
xjson.pprint(open(json_out_fn, "w"), database)
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ class Database(object):
|
|||
def grid(self):
|
||||
""" Return Grid object for database. """
|
||||
self._read_tilegrid()
|
||||
return grid.Grid(self.tilegrid)
|
||||
return grid.Grid(self, self.tilegrid)
|
||||
|
||||
def _read_tile_types(self):
|
||||
for tile_type, db in self.tile_types.items():
|
||||
|
|
|
|||
|
|
@ -98,26 +98,18 @@ class FasmAssembler(object):
|
|||
def enable_feature(self, tile, feature, address, line):
|
||||
gridinfo = self.grid.gridinfo_at_tilename(tile)
|
||||
|
||||
def update_segbit(block_type, bit):
|
||||
def update_segbit(bit):
|
||||
'''Set or clear a single bit in a segment at the given word column and word bit position'''
|
||||
|
||||
bits = gridinfo.bits[block_type]
|
||||
|
||||
seg_baseaddr = bits.base_address
|
||||
seg_word_base = bits.offset
|
||||
|
||||
# Now we have the word column and word bit index
|
||||
# Combine with the segments relative frame position to fully get the position
|
||||
frame_addr = seg_baseaddr + bit.word_column
|
||||
# 2 words per segment
|
||||
word_addr = seg_word_base + bit.word_bit // bitstream.WORD_SIZE_BITS
|
||||
frame_addr = bit.word_column
|
||||
word_addr = bit.word_bit // bitstream.WORD_SIZE_BITS
|
||||
bit_index = bit.word_bit % bitstream.WORD_SIZE_BITS
|
||||
if bit.isset:
|
||||
self.frame_set(frame_addr, word_addr, bit_index, line)
|
||||
else:
|
||||
self.frame_clear(frame_addr, word_addr, bit_index, line)
|
||||
|
||||
segbits = self.db.get_tile_segbits(gridinfo.tile_type)
|
||||
segbits = self.grid.get_tile_segbits_at_tilename(tile)
|
||||
|
||||
self.seen_tile.add(tile)
|
||||
|
||||
|
|
@ -126,9 +118,10 @@ class FasmAssembler(object):
|
|||
any_bits = set()
|
||||
|
||||
try:
|
||||
for block_type, bit in segbits.feature_to_bits(db_k, address):
|
||||
for block_type, bit in segbits.feature_to_bits(gridinfo.bits, db_k,
|
||||
address):
|
||||
any_bits.add(block_type)
|
||||
update_segbit(block_type, bit)
|
||||
update_segbit(bit)
|
||||
except KeyError:
|
||||
raise FasmLookupError(
|
||||
"Segment DB %s, key %s not found from line '%s'" %
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class FasmDisassembler(object):
|
|||
gridinfo = self.grid.gridinfo_at_tilename(tile_name)
|
||||
|
||||
try:
|
||||
tile_segbits = self.db.get_tile_segbits(gridinfo.tile_type)
|
||||
tile_segbits = self.grid.get_tile_segbits_at_tilename(tile_name)
|
||||
except KeyError as e:
|
||||
if not verbose:
|
||||
return
|
||||
|
|
@ -163,3 +163,19 @@ class FasmDisassembler(object):
|
|||
annotations=tuple(annotations),
|
||||
comment=None,
|
||||
)
|
||||
|
||||
def is_zero_feature(self, feature):
|
||||
parts = feature.split('.')
|
||||
tile = parts[0]
|
||||
gridinfo = self.grid.gridinfo_at_tilename(tile)
|
||||
feature = '.'.join(parts[1:])
|
||||
|
||||
db_k = '%s.%s' % (gridinfo.tile_type, feature)
|
||||
segbits = self.grid.get_tile_segbits_at_tilename(tile)
|
||||
any_bits = False
|
||||
for block_type, bit in segbits.feature_to_bits(gridinfo.bits, db_k):
|
||||
if bit.isset:
|
||||
any_bits = True
|
||||
break
|
||||
|
||||
return not any_bits
|
||||
|
|
|
|||
|
|
@ -1,20 +1,6 @@
|
|||
from collections import namedtuple
|
||||
import enum
|
||||
from prjxray import segment_map
|
||||
|
||||
|
||||
class BlockType(enum.Enum):
|
||||
# Frames describing CLB features, interconnect, clocks and IOs.
|
||||
CLB_IO_CLK = 'CLB_IO_CLK'
|
||||
|
||||
# Frames describing block RAM initialization.
|
||||
BLOCK_RAM = 'BLOCK_RAM'
|
||||
|
||||
|
||||
GridLoc = namedtuple('GridLoc', 'grid_x grid_y')
|
||||
GridInfo = namedtuple('GridInfo', 'bits sites tile_type')
|
||||
Bits = namedtuple('Bits', 'base_address frames offset words')
|
||||
BitsInfo = namedtuple('BitsInfo', 'block_type tile bits')
|
||||
from prjxray.grid_types import BlockType, GridLoc, GridInfo, BitAlias, Bits, BitsInfo
|
||||
from prjxray.tile_segbits_alias import TileSegbitsAlias
|
||||
|
||||
|
||||
class Grid(object):
|
||||
|
|
@ -24,7 +10,8 @@ class Grid(object):
|
|||
of segment offsets for particular grid locations and their tile types.
|
||||
"""
|
||||
|
||||
def __init__(self, tilegrid):
|
||||
def __init__(self, db, tilegrid):
|
||||
self.db = db
|
||||
self.tilegrid = tilegrid
|
||||
self.loc = {}
|
||||
self.tileinfo = {}
|
||||
|
|
@ -41,11 +28,22 @@ class Grid(object):
|
|||
for k in tileinfo['bits']:
|
||||
segment_type = BlockType(k)
|
||||
base_address = int(tileinfo['bits'][k]['baseaddr'], 0)
|
||||
|
||||
alias = None
|
||||
if 'alias' in tileinfo['bits'][k]:
|
||||
alias = BitAlias(
|
||||
tile_type=tileinfo['bits'][k]['alias']['type'],
|
||||
start_offset=tileinfo['bits'][k]['alias']
|
||||
['start_offset'],
|
||||
sites=tileinfo['bits'][k]['alias']['sites'],
|
||||
)
|
||||
|
||||
bits[segment_type] = Bits(
|
||||
base_address=base_address,
|
||||
frames=tileinfo['bits'][k]['frames'],
|
||||
offset=tileinfo['bits'][k]['offset'],
|
||||
words=tileinfo['bits'][k]['words'],
|
||||
alias=alias,
|
||||
)
|
||||
|
||||
self.tileinfo[tile] = GridInfo(
|
||||
|
|
@ -103,3 +101,17 @@ class Grid(object):
|
|||
tile_type = gridinfo.tile_type
|
||||
|
||||
return (tile_type, loc.grid_x, -loc.grid_y)
|
||||
|
||||
def get_tile_segbits_at_tilename(self, tilename):
|
||||
gridinfo = self.gridinfo_at_tilename(tilename)
|
||||
|
||||
# Check to see if alias is present
|
||||
any_alias = False
|
||||
for block_type, bits in gridinfo.bits.items():
|
||||
if bits.alias is not None:
|
||||
any_alias = True
|
||||
|
||||
if any_alias:
|
||||
return TileSegbitsAlias(self.db, gridinfo.tile_type, gridinfo.bits)
|
||||
else:
|
||||
return self.db.get_tile_segbits(gridinfo.tile_type)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
from collections import namedtuple
|
||||
import enum
|
||||
|
||||
|
||||
class BlockType(enum.Enum):
|
||||
# Frames describing CLB features, interconnect, clocks and IOs.
|
||||
CLB_IO_CLK = 'CLB_IO_CLK'
|
||||
|
||||
# Frames describing block RAM initialization.
|
||||
BLOCK_RAM = 'BLOCK_RAM'
|
||||
|
||||
|
||||
GridLoc = namedtuple('GridLoc', 'grid_x grid_y')
|
||||
GridInfo = namedtuple('GridInfo', 'bits sites tile_type')
|
||||
BitAlias = namedtuple('BitAlias', 'tile_type start_offset sites')
|
||||
Bits = namedtuple('Bits', 'base_address frames offset words alias')
|
||||
BitsInfo = namedtuple('BitsInfo', 'block_type tile bits')
|
||||
|
|
@ -99,7 +99,7 @@ class TileSegbits(object):
|
|||
self.feature_addresses[base_feature][int(
|
||||
feature[sidx + 1:eidx])] = (block_type, feature)
|
||||
|
||||
def match_bitdata(self, block_type, bits, bitdata):
|
||||
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.
|
||||
|
|
@ -111,7 +111,13 @@ class TileSegbits(object):
|
|||
|
||||
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
|
||||
|
||||
|
|
@ -128,7 +134,7 @@ class TileSegbits(object):
|
|||
if not match:
|
||||
break
|
||||
|
||||
if not match:
|
||||
if not match or skip:
|
||||
continue
|
||||
|
||||
def inner():
|
||||
|
|
@ -140,16 +146,26 @@ class TileSegbits(object):
|
|||
|
||||
yield (tuple(inner()), feature)
|
||||
|
||||
def feature_to_bits(self, feature, address=0):
|
||||
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, bit
|
||||
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, bit
|
||||
yield block_type, self.map_bit_to_frame(
|
||||
block_type, bits_map[block_type], bit)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
""" TileSegbitsAlias provides an alias from one tile type to another.
|
||||
|
||||
TileSegbitsAlias performs severals functions to achieve the alias:
|
||||
- Remaps tile type from the original tile type to the alias tile type
|
||||
- Offsets the bits from the original to the alias type
|
||||
- Renames sites from the original to the alias type
|
||||
- Filters bits outside of the alias.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
from prjxray import bitstream
|
||||
from prjxray.grid_types import Bits
|
||||
|
||||
|
||||
class TileSegbitsAlias(object):
|
||||
def __init__(self, db, tile_type, bits_map):
|
||||
# Name of tile_type that is using the alias
|
||||
self.tile_type = tile_type
|
||||
|
||||
# Name of aliased tile_type
|
||||
self.alias_tile_type = None
|
||||
|
||||
# BlockType -> BitAlias map
|
||||
self.alias = {}
|
||||
|
||||
self.bits_map = bits_map
|
||||
|
||||
# BlockType -> aliased Bits map
|
||||
self.alias_bits_map = {}
|
||||
|
||||
# aliased site name to site name map
|
||||
self.sites_rev_map = {}
|
||||
|
||||
for block_type in bits_map:
|
||||
self.alias[block_type] = bits_map[block_type].alias
|
||||
self.alias_bits_map[block_type] = Bits(
|
||||
base_address=bits_map[block_type].base_address,
|
||||
frames=bits_map[block_type].frames,
|
||||
offset=bits_map[block_type].offset -
|
||||
self.alias[block_type].start_offset,
|
||||
words=bits_map[block_type].words,
|
||||
alias=None,
|
||||
)
|
||||
|
||||
if self.alias_tile_type is None:
|
||||
self.alias_tile_type = self.alias[block_type].tile_type
|
||||
else:
|
||||
assert self.alias_tile_type == self.alias[block_type].tile_type
|
||||
|
||||
self.sites_rev_map[block_type] = {}
|
||||
for site, alias_site in self.alias[block_type].sites.items():
|
||||
assert alias_site not in self.sites_rev_map[block_type]
|
||||
self.sites_rev_map[block_type][alias_site] = site
|
||||
|
||||
self.tile_segbits = db.get_tile_segbits(self.alias_tile_type)
|
||||
|
||||
def map_feature_to_segbits(self, feature):
|
||||
""" Map from the output feature name to the aliased feature name. """
|
||||
parts = feature.split('.')
|
||||
|
||||
assert parts[0] == self.tile_type
|
||||
parts[0] = self.alias_tile_type
|
||||
|
||||
for block_type in self.alias:
|
||||
if len(parts) > 1 and parts[1] in self.alias[block_type].sites:
|
||||
parts[1] = self.alias[block_type].sites[parts[1]]
|
||||
|
||||
return '.'.join(parts)
|
||||
|
||||
def map_feature_from_segbits(self, feature):
|
||||
""" Map from the aliases feature name to the output feature name. """
|
||||
parts = feature.split('.')
|
||||
|
||||
assert parts[0] == self.alias_tile_type
|
||||
parts[0] = self.tile_type
|
||||
|
||||
for block_type in self.alias:
|
||||
if len(parts) > 1 and parts[1] in self.sites_rev_map[block_type]:
|
||||
parts[1] = self.sites_rev_map[block_type][parts[1]]
|
||||
|
||||
return '.'.join(parts)
|
||||
|
||||
def match_filter(self, block_type, query_bit):
|
||||
word = query_bit.word_bit // bitstream.WORD_SIZE_BITS
|
||||
real_word = word - self.alias[block_type].start_offset
|
||||
if real_word < 0 or real_word >= self.bits_map[block_type].words:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def match_bitdata(self, block_type, bits, bitdata):
|
||||
alias_bits = self.alias_bits_map[block_type]
|
||||
|
||||
for bits_found, alias_feature in self.tile_segbits.match_bitdata(
|
||||
block_type, alias_bits, bitdata,
|
||||
match_filter=self.match_filter):
|
||||
feature = self.map_feature_from_segbits(alias_feature)
|
||||
|
||||
yield (bits_found, feature)
|
||||
|
||||
def feature_to_bits(self, bits_map, feature, address=0):
|
||||
alias_feature = self.map_feature_to_segbits(feature)
|
||||
for block_type, bit in self.tile_segbits.feature_to_bits(
|
||||
self.alias_bits_map, alias_feature, address):
|
||||
yield block_type, bit
|
||||
|
|
@ -35,24 +35,9 @@ def bits_to_fasm(db_root, bits_file, verbose, canonical):
|
|||
with open(bits_file) as f:
|
||||
bitdata = bitstream.load_bitdata(f)
|
||||
|
||||
def is_zero_feature(feature):
|
||||
parts = feature.split('.')
|
||||
tile = parts[0]
|
||||
gridinfo = grid.gridinfo_at_tilename(tile)
|
||||
feature = '.'.join(parts[1:])
|
||||
|
||||
db_k = '%s.%s' % (gridinfo.tile_type, feature)
|
||||
segbits = db.get_tile_segbits(gridinfo.tile_type)
|
||||
any_bits = False
|
||||
for block_type, bit in segbits.feature_to_bits(db_k):
|
||||
if bit.isset:
|
||||
any_bits = True
|
||||
|
||||
return not any_bits
|
||||
|
||||
model = fasm.output.merge_and_sort(
|
||||
disassembler.find_features_in_bitstream(bitdata, verbose=verbose),
|
||||
zero_function=is_zero_feature,
|
||||
zero_function=disassembler.is_zero_feature,
|
||||
sort_key=grid.tile_key,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue