diff --git a/.gitignore b/.gitignore index 28f22c0b..a1a839df 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ env *.swp *.swo *.yaml +!test_data/* diff --git a/fpga_interchange/chip_info.py b/fpga_interchange/chip_info.py index 87943f80..0666c843 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,191 @@ 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 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, 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): + label = self.field_label(label_prefix, 'ports') + for port in self.ports: + 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, 'cells')) + bba.u32(len(self.cells)) + + +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 BelChain(): + children_fields = [ + 'patterns', 'coord_configs', 'chain_drivers' + ] + children_types = [ + 'ChainPatternPOD', 'ChainCoordConfigPOD', 'ChainDriverPOD' + ] + + def __init__(self, name, patterns, sites, coord_configs, cells, chain_drivers): + # 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 = [] + 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.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 +1243,7 @@ def __init__(self): self.packages = [] self.wire_types = [] self.global_cells = [] + self.bel_chains = [] # str, constids self.bel_buckets = [] @@ -1068,7 +1259,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 +1271,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..79809fcd 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,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) + bel_chains = {} + for bel_chain in device.device_resource_capnp.belChainsDefinitions.belChains: + assert bel_chain.name not in bel_chains.keys() + drivers_present = bel_chain.which() == "chainDrivers" + bel_chains[bel_chain.name] = BelChain(bel_chain.name, + bel_chain.patterns, + bel_chain.sites, + bel_chain.coordConfigs, + bel_chain.cells, + bel_chain.chainDrivers if drivers_present else None) + + 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..30809a31 --- /dev/null +++ b/test_data/series7_bel_chains.yaml @@ -0,0 +1,26 @@ +belChains: +- 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: + - FDRE + - FDSE + - FDCE + coordConfigs: + - {coord: y, step: -1} # Default + - {coord: y, step: -2} # When crossing clock region