From fc73efd91362fd25b854dec79820e3cf35dd4a89 Mon Sep 17 00:00:00 2001 From: Jan Kowalewski Date: Mon, 10 May 2021 10:41:35 +0200 Subject: [PATCH 1/4] Do not ignore test_data changes Signed-off-by: Jan Kowalewski --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 28f22c0b..a1a839df 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ env *.swp *.swo *.yaml +!test_data/* From 235ebdfcee47cea3538e77bbdc802fb9a3b3f665 Mon Sep 17 00:00:00 2001 From: Jan Kowalewski Date: Mon, 10 May 2021 10:41:45 +0200 Subject: [PATCH 2/4] fpga_interchange: introduce BEL chains feature Signed-off-by: Jan Kowalewski --- fpga_interchange/chip_info.py | 150 ++++++++++++++++++++++++- fpga_interchange/nextpnr.py | 4 +- fpga_interchange/populate_chip_info.py | 16 ++- test_data/series7_bel_chains.yaml | 14 +++ 4 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 test_data/series7_bel_chains.yaml diff --git a/fpga_interchange/chip_info.py b/fpga_interchange/chip_info.py index 87943f80..dd5709f4 100644 --- a/fpga_interchange/chip_info.py +++ b/fpga_interchange/chip_info.py @@ -19,6 +19,11 @@ class ConstraintType(Enum): TAG_REQUIRES = 1 +class ChainCoordinate(Enum): + X = 0 + Y = 1 + + class BelInfo(): str_id_fields = ['ports'] int_fields = ['types', 'wires'] @@ -646,6 +651,147 @@ def append_bba(self, bba, label_prefix): bba.u32(len(getattr(self, field))) +class ChainPatternConfig(): + def __init__(self, type, port): + self.type = type + self.port = port + + def append_children_bba(self, bba, label_prefix): + pass + + def append_bba(self, bba, label_prefix): + bba.str_id(self.type) + bba.str_id(self.port) + + +class ChainPattern(): + children_fields = [ + 'source', 'sink' + ] + children_types = [ + 'ChainPatternConfigPOD', 'ChainPatternConfigPOD' + ] + + def __init__(self, source, sink): + self.source = ChainPatternConfig(source.type, source.port) + self.sink = ChainPatternConfig(sink.type, sink.port) + + def field_label(self, label_prefix, field): + prefix = '{}.{}'.format(label_prefix, field) + return prefix + + def append_children_bba(self, bba, label_prefix): + label = label_prefix + + for field, field_type in zip(self.children_fields, + self.children_types): + prefix = self.field_label(label, field) + value = getattr(self, field) + value.append_children_bba(bba, prefix) + + bba.label(prefix, field_type) + value.append_bba(bba, prefix) + + def append_bba(self, bba, label_prefix): + for field in self.children_fields: + bba.ref(self.field_label(label_prefix, field)) + bba.u32(1) + + +class ChainCoordConfig(): + def __init__(self, coord, step): + self.coord = ChainCoordinate[str(coord).upper()] + self.step = step + + def append_children_bba(self, bba, label_prefix): + pass + + def append_bba(self, bba, label_prefix): + bba.u8(self.coord.value) + bba.u8(self.step) + bba.u16(0) + + +class ChainCell(): + def __init__(self, cell, input_pins, output_pins): + self.cell = cell + + def append_children_bba(self, bba, label_prefix): + pass + + def append_bba(self, bba, label_prefix): + bba.str_id(self.cell) + + +class BelChain(): + children_fields = [ + 'patterns', 'coord_configs' + ] + children_types = [ + 'ChainPatternPOD', 'ChainCoordConfigPOD' + ] + + def __init__(self, name, patterns, sites, coord_configs, cells): + # Chain name + self.name = name + + # Chain patterns + self.patterns = [] + for pattern in patterns: + self.patterns.append(ChainPattern(pattern.source, pattern.sink)) + + # Sites for which chain patterns apply + self.sites = sites + + # Coordinates configurations + # which coordinate by what step should be incremented + self.coord_configs = [] + if coord_configs is not None: + for coord_config in coord_configs: + self.coord_configs.append(ChainCoordConfig(coord_config.coord, coord_config.step)) + + # Chain cells used in BEL chain + self.cells = cells + + 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, 'sites'), 'constids') + for site in self.sites: + bba.str_id(site) + + bba.label(self.field_label(label_prefix, 'cells'), 'constids') + for cell in self.cells: + bba.str_id(cell) + + for field, field_type in zip(self.children_fields, + self.children_types): + prefix = self.field_label(label, field) + for value in getattr(self, field): + value.append_children_bba(bba, prefix) + + bba.label(prefix, field_type) + for value in getattr(self, field): + value.append_bba(bba, prefix) + + def append_bba(self, bba, label_prefix): + bba.str_id(self.name) + + bba.ref(self.field_label(label_prefix, 'sites')) + bba.u32(len(self.sites)) + + bba.ref(self.field_label(label_prefix, 'cells')) + bba.u32(len(self.cells)) + + for field in self.children_fields: + bba.ref(self.field_label(label_prefix, field)) + bba.u32(len(getattr(self, field))) + + class PackagePin(): def __init__(self): self.package_pin = '' @@ -1053,6 +1199,7 @@ def __init__(self): self.packages = [] self.wire_types = [] self.global_cells = [] + self.bel_chains = [] # str, constids self.bel_buckets = [] @@ -1068,7 +1215,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', 'bel_chains' ] children_types = [ 'TileTypeInfoPOD', @@ -1080,6 +1227,7 @@ def append_bba(self, bba, label_prefix): 'GlobalCellPOD', 'MacroPOD', 'MacroExpansionPOD', + 'BelChainPOD', ] for field, field_type in zip(children_fields, children_types): prefix = '{}.{}'.format(label, field) diff --git a/fpga_interchange/nextpnr.py b/fpga_interchange/nextpnr.py index 2bbe4124..87a934ad 100644 --- a/fpga_interchange/nextpnr.py +++ b/fpga_interchange/nextpnr.py @@ -81,5 +81,5 @@ 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)) diff --git a/fpga_interchange/populate_chip_info.py b/fpga_interchange/populate_chip_info.py index 24287583..fa19a5d4 100644 --- a/fpga_interchange/populate_chip_info.py +++ b/fpga_interchange/populate_chip_info.py @@ -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, BelChain from fpga_interchange.constraints.model import Tag, Placement, \ ImpliesConstraint, RequiresConstraint from fpga_interchange.constraint_generator import ConstraintPrototype @@ -1835,6 +1835,18 @@ 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) + bel_chains = {} + for bel_chain in device.device_resource_capnp.belChainsDefinitions.belChains: + assert bel_chain.name not in bel_chains.keys() + cfgs_present = bel_chain.which() == "coordConfigs" + bel_chains[bel_chain.name] = BelChain(bel_chain.name, + bel_chain.patterns, + bel_chain.sites, + bel_chain.coordConfigs if cfgs_present else None, + bel_chain.cells) + + chip_info.bel_chains.append(bel_chains[bel_chain.name]) + for tile_type_index, tile_type in enumerate( device.device_resource_capnp.tileTypeList): flattened_tile_type = FlattenedTileType( diff --git a/test_data/series7_bel_chains.yaml b/test_data/series7_bel_chains.yaml new file mode 100644 index 00000000..a335317e --- /dev/null +++ b/test_data/series7_bel_chains.yaml @@ -0,0 +1,14 @@ +belChains: + - name: carryChain + patterns: + - {source: {type: "CARRY4", port: "CO[3]"}, sink: {type: "CARRY4", port: "CI"}} + sites: + - SLICEL + - SLICEM + cells: + - XORCY + - MUXCY + - CARRY4 + coordConfigs: + - {coord: y, step: -1} # Default + - {coord: y, step: -2} # When crossing clock region From 8ea36fb0c140afa11335a68898d6786741b80675 Mon Sep 17 00:00:00 2001 From: Jan Kowalewski Date: Thu, 20 May 2021 12:18:21 +0200 Subject: [PATCH 3/4] fpga_interchange: add chain drivers Signed-off-by: Jan Kowalewski --- fpga_interchange/chip_info.py | 41 ++++++++++++++++++++++---- fpga_interchange/populate_chip_info.py | 7 +++-- test_data/series7_bel_chains.yaml | 5 ++-- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/fpga_interchange/chip_info.py b/fpga_interchange/chip_info.py index dd5709f4..abd7688d 100644 --- a/fpga_interchange/chip_info.py +++ b/fpga_interchange/chip_info.py @@ -698,6 +698,30 @@ def append_bba(self, bba, label_prefix): bba.u32(1) +class ChainDriver(): + def __init__(self, ports, bels): + self.ports = ports + self.bels = bels + + def field_label(self, label_prefix, field): + prefix = '{}.{}'.format(label_prefix, field) + return prefix + + def append_children_bba(self, bba, label_prefix): + bba.label(self.field_label(label_prefix, 'ports'), 'constids') + for port in self.ports: + bba.str_id(port) + bba.label(self.field_label(label_prefix, 'bels'), 'constids') + for bel in self.bels: + bba.str_id(bel) + + def append_bba(self, bba, label_prefix): + bba.ref(self.field_label(label_prefix, 'ports')) + bba.u32(len(self.ports)) + + bba.ref(self.field_label(label_prefix, 'bels')) + bba.u32(len(self.bels)) + class ChainCoordConfig(): def __init__(self, coord, step): self.coord = ChainCoordinate[str(coord).upper()] @@ -725,13 +749,13 @@ def append_bba(self, bba, label_prefix): class BelChain(): children_fields = [ - 'patterns', 'coord_configs' + 'patterns', 'coord_configs', 'chain_drivers' ] children_types = [ - 'ChainPatternPOD', 'ChainCoordConfigPOD' + 'ChainPatternPOD', 'ChainCoordConfigPOD', 'ChainDriverPOD' ] - def __init__(self, name, patterns, sites, coord_configs, cells): + def __init__(self, name, patterns, sites, coord_configs, cells, chain_drivers): # Chain name self.name = name @@ -746,13 +770,18 @@ def __init__(self, name, patterns, sites, coord_configs, cells): # Coordinates configurations # which coordinate by what step should be incremented self.coord_configs = [] - if coord_configs is not None: - for coord_config in coord_configs: - self.coord_configs.append(ChainCoordConfig(coord_config.coord, coord_config.step)) + for coord_config in coord_configs: + self.coord_configs.append(ChainCoordConfig(coord_config.coord, coord_config.step)) # Chain cells used in BEL chain self.cells = cells + # Optional drivers of the cells used in BEL chain + self.chain_drivers = [] + if chain_drivers is not None: + for driver in chain_drivers: + self.chain_drivers.append(ChainDriver(driver.ports, driver.bels)) + def field_label(self, label_prefix, field): prefix = '{}.{}.{}'.format(label_prefix, self.name, field) return prefix diff --git a/fpga_interchange/populate_chip_info.py b/fpga_interchange/populate_chip_info.py index fa19a5d4..79809fcd 100644 --- a/fpga_interchange/populate_chip_info.py +++ b/fpga_interchange/populate_chip_info.py @@ -1838,12 +1838,13 @@ def populate_chip_info(device, constids, device_config): bel_chains = {} for bel_chain in device.device_resource_capnp.belChainsDefinitions.belChains: assert bel_chain.name not in bel_chains.keys() - cfgs_present = bel_chain.which() == "coordConfigs" + drivers_present = bel_chain.which() == "chainDrivers" bel_chains[bel_chain.name] = BelChain(bel_chain.name, bel_chain.patterns, bel_chain.sites, - bel_chain.coordConfigs if cfgs_present else None, - bel_chain.cells) + bel_chain.coordConfigs, + bel_chain.cells, + bel_chain.chainDrivers if drivers_present else None) chip_info.bel_chains.append(bel_chains[bel_chain.name]) diff --git a/test_data/series7_bel_chains.yaml b/test_data/series7_bel_chains.yaml index a335317e..ae9750fd 100644 --- a/test_data/series7_bel_chains.yaml +++ b/test_data/series7_bel_chains.yaml @@ -6,9 +6,10 @@ belChains: - SLICEL - SLICEM cells: - - XORCY - - MUXCY - CARRY4 + chainDrivers: # Place driver cell of S port to a proper BEL + - {ports: ["S[0]", "S[1]", "S[2]", "S[3]"], + bels: ["LUT6", "LUT_OR_MEM6"]} coordConfigs: - {coord: y, step: -1} # Default - {coord: y, step: -2} # When crossing clock region From bce222bd53f70eefcc226e74b2040e45440e0cc7 Mon Sep 17 00:00:00 2001 From: Alessandro Comodi Date: Thu, 27 May 2021 15:19:45 +0200 Subject: [PATCH 4/4] WIP: add BEL to use for specific inputs when driven by specific cells Signed-off-by: Alessandro Comodi --- fpga_interchange/chip_info.py | 59 +++++++++++++++++++------------ test_data/series7_bel_chains.yaml | 37 ++++++++++++------- 2 files changed, 61 insertions(+), 35 deletions(-) diff --git a/fpga_interchange/chip_info.py b/fpga_interchange/chip_info.py index abd7688d..0666c843 100644 --- a/fpga_interchange/chip_info.py +++ b/fpga_interchange/chip_info.py @@ -698,29 +698,55 @@ def append_bba(self, bba, label_prefix): bba.u32(1) +class ChainDriverPortBel(): + def __init__(self, name, bel): + self.name = name + self.bel = bel + + def field_label(self, label_prefix, field): + prefix = '{}.{}.{}'.format(label_prefix, self.name, field) + return prefix + + def append_children_bba(self, bba, label_prefix): + pass + + def append_bba(self, bba, label_prefix): + bba.str_id(self.name) + bba.str_id(self.bel) + + class ChainDriver(): - def __init__(self, ports, bels): - self.ports = ports - self.bels = bels + def __init__(self, ports, cells): + self.ports = [] + self.cells = cells + + for port in ports: + self.ports.append(ChainDriverPortBel(port.name, port.bel)) def field_label(self, label_prefix, field): prefix = '{}.{}'.format(label_prefix, field) return prefix def append_children_bba(self, bba, label_prefix): - bba.label(self.field_label(label_prefix, 'ports'), 'constids') + label = self.field_label(label_prefix, 'ports') for port in self.ports: - bba.str_id(port) - bba.label(self.field_label(label_prefix, 'bels'), 'constids') - for bel in self.bels: - bba.str_id(bel) + port.append_children_bba(bba, label) + + bba.label(label, 'ChainDriverPortBelPOD') + for port in self.ports: + port.append_bba(bba, label) + + bba.label(self.field_label(label_prefix, 'cells'), 'constids') + for cell in self.cells: + bba.str_id(cell) def append_bba(self, bba, label_prefix): bba.ref(self.field_label(label_prefix, 'ports')) bba.u32(len(self.ports)) - bba.ref(self.field_label(label_prefix, 'bels')) - bba.u32(len(self.bels)) + bba.ref(self.field_label(label_prefix, 'cells')) + bba.u32(len(self.cells)) + class ChainCoordConfig(): def __init__(self, coord, step): @@ -736,17 +762,6 @@ def append_bba(self, bba, label_prefix): bba.u16(0) -class ChainCell(): - def __init__(self, cell, input_pins, output_pins): - self.cell = cell - - def append_children_bba(self, bba, label_prefix): - pass - - def append_bba(self, bba, label_prefix): - bba.str_id(self.cell) - - class BelChain(): children_fields = [ 'patterns', 'coord_configs', 'chain_drivers' @@ -780,7 +795,7 @@ def __init__(self, name, patterns, sites, coord_configs, cells, chain_drivers): self.chain_drivers = [] if chain_drivers is not None: for driver in chain_drivers: - self.chain_drivers.append(ChainDriver(driver.ports, driver.bels)) + self.chain_drivers.append(ChainDriver(driver.ports, driver.cells)) def field_label(self, label_prefix, field): prefix = '{}.{}.{}'.format(label_prefix, self.name, field) diff --git a/test_data/series7_bel_chains.yaml b/test_data/series7_bel_chains.yaml index ae9750fd..30809a31 100644 --- a/test_data/series7_bel_chains.yaml +++ b/test_data/series7_bel_chains.yaml @@ -1,15 +1,26 @@ belChains: - - name: carryChain - patterns: - - {source: {type: "CARRY4", port: "CO[3]"}, sink: {type: "CARRY4", port: "CI"}} - sites: - - SLICEL - - SLICEM +- name: carryChain + patterns: + - {source: {type: "CARRY4", port: "CO[3]"}, sink: {type: "CARRY4", port: "CI"}} + sites: + - SLICEL + - SLICEM + cells: + - CARRY4 + chainDrivers: # Place driver cell of S port to a proper BEL + - ports: + - name: S[0] + bel: AFF + - name: S[1] + bel: BFF + - name: S[2] + bel: CFF + - name: S[3] + bel: DFF cells: - - CARRY4 - chainDrivers: # Place driver cell of S port to a proper BEL - - {ports: ["S[0]", "S[1]", "S[2]", "S[3]"], - bels: ["LUT6", "LUT_OR_MEM6"]} - coordConfigs: - - {coord: y, step: -1} # Default - - {coord: y, step: -2} # When crossing clock region + - FDRE + - FDSE + - FDCE + coordConfigs: + - {coord: y, step: -1} # Default + - {coord: y, step: -2} # When crossing clock region