Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add interchange clustering definition #91

Merged
merged 2 commits into from
Jun 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ env
*.swp
*.swo
*.yaml
!test_data/*
102 changes: 99 additions & 3 deletions fpga_interchange/chip_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#
# SPDX-License-Identifier: ISC
from enum import Enum
from itertools import product

# Note: Increment by 1 ChipInfo.version number each time schema changes to
# allow nextpnr binary to detect changes to schema.
Expand Down Expand Up @@ -646,6 +647,99 @@ def append_bba(self, bba, label_prefix):
bba.u32(len(getattr(self, field)))


class ClusterCellPort():
def __init__(self, cell, port):
self.cell = cell
self.port = port

def append_children_bba(self, bba, label_prefix):
pass

def append_bba(self, bba, label_prefix):
bba.str_id(self.cell)
bba.str_id(self.port)


class ChainablePort():
def __init__(self, cell_source, cell_sink, bel_source, bel_sink, x_offset,
y_offset):
self.cell_source = cell_source
self.cell_sink = cell_sink
self.bel_source = bel_source
self.bel_sink = bel_sink
self.avg_x_offset = x_offset
self.avg_y_offset = y_offset

def append_children_bba(self, bba, label_prefix):
pass

def append_bba(self, bba, label_prefix):
bba.str_id(self.cell_source)
bba.str_id(self.cell_sink)
bba.str_id(self.bel_source)
bba.str_id(self.bel_sink)
bba.u16(self.avg_x_offset)
bba.u16(self.avg_y_offset)


class Cluster():
fields = ['chainable_ports', 'cluster_cell_ports']
field_types = ['ChainablePortPOD', 'ClusterCellPortPOD']

def __init__(self, name, chainable_ports, root_cell_types, cluster_cells):
# Chain name
self.name = name

# Chain cells used in BEL chain
self.root_cell_types = root_cell_types

# Chainable ports
self.chainable_ports = []
for port in chainable_ports:
self.chainable_ports.append(
ChainablePort(port["cell_source"], port["cell_sink"],
port["bel_source"], port["bel_sink"],
port["avg_x_offset"], port["avg_y_offset"]))

# Optional cell <-> port mapping to bind cells to a specific cluster
self.cluster_cell_ports = []
for cell in cluster_cells:
for cell, port in product(cell["cells"], cell["ports"]):
self.cluster_cell_ports.append(ClusterCellPort(cell, port))

def field_label(self, label_prefix, field):
prefix = '{}.{}.{}'.format(label_prefix, self.name, field)
return prefix

def append_children_bba(self, bba, label_prefix):
label = label_prefix

bba.label(
self.field_label(label_prefix, 'root_cell_types'), 'constids')
for cell_type in self.root_cell_types:
bba.str_id(cell_type)

for field, field_type in zip(self.fields, self.field_types):
for value in getattr(self, field):
value.append_children_bba(
bba, self.field_label(label_prefix, field))

for field, field_type in zip(self.fields, self.field_types):
bba.label(self.field_label(label_prefix, field), field_type)
for value in getattr(self, field):
value.append_bba(bba, self.field_label(label_prefix, field))

def append_bba(self, bba, label_prefix):
bba.str_id(self.name)

bba.ref(self.field_label(label_prefix, 'root_cell_types'))
bba.u32(len(self.root_cell_types))

for field in self.fields:
bba.ref(self.field_label(label_prefix, field))
bba.u32(len(getattr(self, field)))


class PackagePin():
def __init__(self):
self.package_pin = ''
Expand Down Expand Up @@ -1041,8 +1135,8 @@ def __init__(self):
self.name = ''
self.generator = ''

# Note: Increment by 1 this whenever schema changes.
self.version = 10
# Note: Increment by 1 this whenever schema or the nextpnr chip database structure changes.
self.version = 11
self.width = 0
self.height = 0

Expand All @@ -1053,6 +1147,7 @@ def __init__(self):
self.packages = []
self.wire_types = []
self.global_cells = []
self.clusters = []

# str, constids
self.bel_buckets = []
Expand All @@ -1068,7 +1163,7 @@ def append_bba(self, bba, label_prefix):

children_fields = [
'tile_types', 'sites', 'tiles', 'nodes', 'packages', 'wire_types',
'global_cells', 'macros', 'macro_rules'
'global_cells', 'macros', 'macro_rules', 'clusters'
]
children_types = [
'TileTypeInfoPOD',
Expand All @@ -1080,6 +1175,7 @@ def append_bba(self, bba, label_prefix):
'GlobalCellPOD',
'MacroPOD',
'MacroExpansionPOD',
'ClusterPOD',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, done

]
for field, field_type in zip(children_fields, children_types):
prefix = '{}.{}'.format(label, field)
Expand Down
6 changes: 4 additions & 2 deletions fpga_interchange/nextpnr.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,7 @@ def pop(self):

def check_labels(self):
refs_and_labels = self.refs & self.labels
assert len(refs_and_labels) == len(self.refs)
assert len(refs_and_labels) == len(self.labels)
assert len(refs_and_labels) == len(self.refs), "{} vs. {}".format(
len(refs_and_labels), len(self.refs))
assert len(refs_and_labels) == len(self.labels), "{} vs. {}".format(
len(refs_and_labels), len(self.labels))
36 changes: 32 additions & 4 deletions fpga_interchange/populate_chip_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
TileWireRef, CellBelMap, ParameterPins, CellBelPin, ConstraintTag, \
CellConstraint, ConstraintType, Package, PackagePin, LutCell, \
LutElement, LutBel, CellParameter, DefaultCellConnections, DefaultCellConnection, \
WireType, Macro, MacroNet, MacroPortInst, MacroCellInst, MacroExpansion, MacroParamMapRule, MacroParamRuleType, MacroParameter, GlobalCell, GlobalCellPin

WireType, Macro, MacroNet, MacroPortInst, MacroCellInst, MacroExpansion, \
MacroParamMapRule, MacroParamRuleType, MacroParameter, GlobalCell, GlobalCellPin, Cluster
from fpga_interchange.constraints.model import Tag, Placement, \
ImpliesConstraint, RequiresConstraint
from fpga_interchange.constraint_generator import ConstraintPrototype
Expand Down Expand Up @@ -191,7 +191,8 @@ def emit(self, lut_elements):

class FlattenedTileType():
def __init__(self, device, tile_type_index, tile_type, cell_bel_mapper,
constraints, lut_elements, disabled_routethrus):
constraints, lut_elements, disabled_routethrus,
disabled_site_pips):
self.tile_type_name = device.strs[tile_type.name]
self.tile_type = tile_type

Expand All @@ -207,6 +208,8 @@ def __init__(self, device, tile_type_index, tile_type, cell_bel_mapper,
self.lut_elements = []
self.lut_elements_map = {}

self.disabled_site_pips = disabled_site_pips

# Add tile wires
self.tile_wire_to_wire_in_tile_index = {}
for wire_in_tile_index, wire in enumerate(tile_type.wires):
Expand Down Expand Up @@ -555,6 +558,21 @@ def add_site_type(self,
dst_bel_pin = site_pip.outpin
dst_site_wire_idx = bel_pin_to_site_wire_index[dst_bel_pin]

src_pin_name_idx = site_type.belPins[src_bel_pin].name
dst_pin_name_idx = site_type.belPins[dst_bel_pin].name
bel_name_idx = site_type.bels[bel_idx].name

disable_pip = False
for dis_pip in self.disabled_site_pips:
if device.strs[bel_name_idx] in dis_pip["bels"] and \
dis_pip["ipin"] == device.strs[src_pin_name_idx] and \
dis_pip["opin"] == device.strs[dst_pin_name_idx]:
disable_pip = True
break

if disable_pip:
continue

self.add_site_pip(src_site_wire_idx, dst_site_wire_idx, site_index,
idx)

Expand Down Expand Up @@ -1762,8 +1780,10 @@ def populate_chip_info(device, constids, device_config):
bel_bucket_seeds = device_config.get('buckets', [])
global_buffer_bels = device_config.get('global_buffer_bels', [])
disabled_routethrus = device_config.get('disabled_routethroughs', [])
disabled_site_pips = device_config.get('disabled_site_pips', [])
disabled_cell_bel_map = device_config.get('disabled_cell_bel_map', [])
global_buffer_cells = device_config.get('global_buffer_cells', [])
clusters = device_config.get('clusters', [])

cell_bel_mapper = CellBelMapper(device, constids, disabled_cell_bel_map)

Expand Down Expand Up @@ -1835,11 +1855,19 @@ def populate_chip_info(device, constids, device_config):
assert lut_element.site not in lut_elements
lut_elements[lut_element.site] = LutElementsEmitter(lut_element.luts)

for cluster in clusters:
cluster_name = cluster["name"]
cluster_obj = Cluster(cluster_name, cluster.get("chainable_ports", []),
cluster["root_cell_types"],
cluster.get("cluster_cells", []))

chip_info.clusters.append(cluster_obj)

for tile_type_index, tile_type in enumerate(
device.device_resource_capnp.tileTypeList):
flattened_tile_type = FlattenedTileType(
device, tile_type_index, tile_type, cell_bel_mapper, constraints,
lut_elements, disabled_routethrus)
lut_elements, disabled_routethrus, disabled_site_pips)

tile_type_info = flattened_tile_type.create_tile_type_info(
cell_bel_mapper)
Expand Down
Empty file.
58 changes: 58 additions & 0 deletions test_data/series7_device_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,61 @@ disabled_cell_bel_map:
- TFF
- IFF
- OUTFF
disabled_site_pips:
- bels:
- A6LUT
- B6LUT
- C6LUT
- D6LUT
ipin: A6
opin: O6
clusters:
- name: CARRY_CHAIN
chainable_ports:
- cell_source: CO[3]
cell_sink: CI
bel_source: CO3
bel_sink: CIN
avg_x_offset: 0
avg_y_offset: -1
root_cell_types:
- CARRY4
cluster_cells:
- cells:
- LUT1
- LUT2
- LUT3
- LUT4
- LUT5
- LUT6
ports:
- S[3]
- S[2]
- S[1]
- S[0]
- cells:
- FDRE
- FDSE
- FDCE
- FDPE
ports:
- O[3]
- O[2]
- O[1]
- O[0]
- name: LUT_FF
root_cell_types:
- FDRE
- FDSE
- FDCE
- FDPE
cluster_cells:
- cells:
- LUT1
- LUT2
- LUT3
- LUT4
- LUT5
- LUT6
ports:
- D