def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--schema_dir', required=True)
    parser.add_argument('--output_dir', required=True)
    parser.add_argument('--device', required=True)
    parser.add_argument('--device_config', required=True)

    args = parser.parse_args()
    interchange = Interchange(args.schema_dir)

    with open(args.device, 'rb') as f:
        device = interchange.read_device_resources(f)

    with open(args.device_config, 'r') as f:
        device_config = yaml.safe_load(f.read())

    const_ids = Enumerator()

    # ID = 0 is always the empty string!
    assert const_ids.get_index('') == 0

    if 'global_buffers' in device_config:
        global_buffers = device_config['global_buffers']
    else:
        global_buffers = []

    chip_info = populate_chip_info(device, const_ids, global_buffers,
                                   device_config['buckets'])

    with open(os.path.join(args.output_dir, 'chipdb.bba'), 'w') as f:
        bba = BbaWriter(f, const_ids)
        bba.pre("#include \"nextpnr.h\"")
        bba.pre("NEXTPNR_NAMESPACE_BEGIN")
        bba.post("NEXTPNR_NAMESPACE_END")
        bba.push("chipdb_blob")

        root_prefix = 'chip_info'
        bba.ref(root_prefix, root_prefix)
        chip_info.append_bba(bba, root_prefix)

        bba.label(chip_info.strings_label(root_prefix), 'strings_slice')
        bba.ref('strings_data')
        bba.u32(len(const_ids.values) - 1)

        bba.label('strings_data', 'strings')
        for s in const_ids.values[1:]:
            bba.str(s)

        bba.pop()

    bba.check_labels()

    with open(os.path.join(args.output_dir, 'constids.txt'), 'w') as f:
        for s in const_ids.values[1:]:
            print('X({})'.format(s), file=f)
    def test_device_rapidyaml(self):
        return
        phys_netlist = example_physical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])

        with open(
                os.path.join(os.environ['DEVICE_RESOURCE_PATH'],
                             phys_netlist.part + '.device'), 'rb') as f:
            dev_message = interchange.read_device_resources_raw(f)

        self.round_trip_rapidyaml('device', dev_message)
Ejemplo n.º 3
0
def main():
    parser = argparse.ArgumentParser(
        description=
        "Create an example netlist, suitable for use with Vivado 2019.2")

    parser.add_argument('--schema_dir', required=True)
    parser.add_argument('--logical_netlist', required=True)
    parser.add_argument('--physical_netlist', required=True)
    parser.add_argument('--xdc', required=True)

    args = parser.parse_args()

    interchange = Interchange(args.schema_dir)
    logical_netlist = example_logical_netlist()
    logical_netlist_capnp = logical_netlist.convert_to_capnp(interchange)
    phys_netlist = example_physical_netlist()
    phys_netlist_capnp = phys_netlist.convert_to_capnp(interchange)

    with open(args.logical_netlist, 'wb') as f:
        write_capnp_file(logical_netlist_capnp, f)

    with open(args.physical_netlist, 'wb') as f:
        write_capnp_file(phys_netlist_capnp, f)

    with open(args.xdc, 'w') as f:
        f.write(example_xdc())
Ejemplo n.º 4
0
def get_schema(schema_dir, schema, schema_path=None):
    """ Returns capnp schema based on directory of schemas, schema type.

    schema_dir (str): Path to directory containing schemas.
    schema (str): Schema type to return, either device, logical, physical.
    schema_path (str): Optional '.' seperated path to locate a schema.

    Returns capnp schema.

    """
    schemas = Interchange(schema_dir)

    schema_map = {
        'device': schemas.device_resources_schema,
        'logical': schemas.logical_netlist_schema,
        'physical': schemas.physical_netlist_schema,
    }

    # Make sure schema_map is complete.
    for schema_str in SCHEMAS:
        assert schema_str in schema_map

    if schema_path is None:
        default_path = {
            'device': ['Device'],
            'logical': ['Netlist'],
            'physical': ['PhysNetlist'],
        }
        path = default_path[schema]
    else:
        path = schema_path.split('.')

    schema = follow_path(schema_map[schema], path)

    return schema
    def test_get_schemas(self):
        schema_dir = os.environ['INTERCHANGE_SCHEMA_PATH']

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])

        self.assertSameSchema(interchange.device_resources_schema.Device,
                              get_schema(schema_dir, 'device'))

        self.assertSameSchema(interchange.device_resources_schema.Device,
                              get_schema(schema_dir, 'device', 'Device'))

        self.assertSameSchema(
            interchange.device_resources_schema.Device.SiteType,
            get_schema(schema_dir, 'device', 'Device.SiteType'))

        self.assertSameSchema(interchange.logical_netlist_schema.Netlist,
                              get_schema(schema_dir, 'logical'))

        self.assertSameSchema(interchange.logical_netlist_schema.Netlist,
                              get_schema(schema_dir, 'logical', 'Netlist'))

        self.assertSameSchema(interchange.physical_netlist_schema.PhysNetlist,
                              get_schema(schema_dir, 'physical'))

        self.assertSameSchema(
            interchange.physical_netlist_schema.PhysNetlist,
            get_schema(schema_dir, 'physical', 'PhysNetlist'))
Ejemplo n.º 6
0
def main():
    parser = argparse.ArgumentParser(description=__doc__)

    parser.add_argument(
        '--schema_dir',
        required=True,
        help="Path to the FPGA interchange schemas directory.")
    parser.add_argument(
        '--family', required=True, help="Device family. E.g. xc7, xcu, etc.")
    parser.add_argument('device_resources', help="Device resources file.")
    parser.add_argument('logical_netlist', help="Logical netlist file.")
    parser.add_argument('physical_netlist', help="Physical netlist file.")
    parser.add_argument('fasm_file', help="FASM output file.")

    args = parser.parse_args()

    interchange = Interchange(args.schema_dir)

    family_map = {
        "xc7": XC7FasmGenerator,
    }

    device_resources = args.device_resources
    logical_net = args.logical_netlist
    physical_net = args.physical_netlist
    fasm_file = args.fasm_file

    fasm_generator = family_map[args.family](interchange, device_resources,
                                             logical_net, physical_net)
    fasm_generator.fill_features()
    fasm_generator.output_fasm(fasm_file)
def main():

    parser = argparse.ArgumentParser(description="Generates testarch FPGA")
    parser.add_argument("--schema_dir",
                        required=True,
                        help="Path to FPGA interchange capnp schema files")

    args = parser.parse_args()

    # Run the test architecture generator
    gen = TestArchGenerator()
    gen.generate()

    # Initialize the writer (or "serializer")
    interchange = Interchange(args.schema_dir)
    writer = DeviceResourcesCapnp(
        gen.device,
        interchange.device_resources_schema,
        interchange.logical_netlist_schema,
    )

    # Serialize
    device_resources = writer.to_capnp()
    with open("device_resources.device.gz", "wb") as fp:
        write_capnp_file(
            device_resources,
            fp)  #, compression_format=CompressionFormat.UNCOMPRESSED)
Ejemplo n.º 8
0
    def test_logical_netlist(self):
        logical_netlist = example_logical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])

        with tempfile.NamedTemporaryFile('w+b') as f:
            netlist_capnp = logical_netlist.convert_to_capnp(interchange)
            write_capnp_file(netlist_capnp, f)
            f.seek(0)

            read_logical_netlist = LogicalNetlist.read_from_capnp(
                f, interchange)

        self.assertEqual(read_logical_netlist.name, logical_netlist.name)
        self.assertEqual(read_logical_netlist.top_instance,
                         logical_netlist.top_instance)

        self.assertEqual(read_logical_netlist.libraries.keys(),
                         logical_netlist.libraries.keys())
        for library_name, library in logical_netlist.libraries.items():
            read_library = read_logical_netlist.libraries[library_name]
            self.assertEqual(library.cells.keys(), read_library.cells.keys())
            for cell_name, cell in library.cells.items():
                read_cell = read_library.cells[cell_name]

                self.assertEqual(cell.name, read_cell.name)
                self.assertEqual(cell.property_map, read_cell.property_map)
                self.assertEqual(cell.view, read_cell.view)
                self.assertEqual(cell.nets.keys(), read_cell.nets.keys())
                self.assertEqual(cell.ports.keys(), read_cell.ports.keys())
                self.assertEqual(cell.cell_instances.keys(),
                                 read_cell.cell_instances.keys())
    def test_physical_netlist_convert(self):
        phys_netlist = example_physical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])
        netlist_capnp = phys_netlist.convert_to_capnp(interchange)

        self.round_read_write_message('physical', netlist_capnp)
    def test_logical_netlist_yaml(self):
        logical_netlist = example_logical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])
        netlist_capnp = logical_netlist.convert_to_capnp(interchange)

        self.round_trip_yaml('log', netlist_capnp)
    def test_physical_netlist_rapidyaml(self):
        phys_netlist = example_physical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])
        netlist_capnp = phys_netlist.convert_to_capnp(interchange)

        self.round_trip_rapidyaml('phys', netlist_capnp)
Ejemplo n.º 12
0
def init(fileName='', device_file=DEVICE_FILE, schema_dir=SCHEMA_DIR):
    """
    Set up the environment for __main__.
    Also useful to run after an import for debugging/testing
    Parameters:
        fileName (str) - Name of file to pass to XDLRC constructor
    """

    device_schema = Interchange(SCHEMA_DIR).device_resources_schema.Device
    return XDLRC(read_capnp_file(device_schema, device_file), fileName, FAMILY, PKG, GRADE)
Ejemplo n.º 13
0
    def test_simple_placement(self):
        netlist = example_logical_netlist()
        cells = create_constraint_cells_from_netlist(
            netlist, filtered_out={'GND', 'VCC'})

        phys_netlist = example_physical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])

        with open(
                os.path.join(os.environ['DEVICE_RESOURCE_PATH'],
                             phys_netlist.part + '.device'), 'rb') as f:
            dev_message = interchange.read_device_resources_raw(f)

        dev_message = dev_message.as_builder()

        path = os.path.join(__dir__, 'data', 'series7_constraints.yaml')
        with open(path, 'rb') as f:
            patch_capnp(dev_message, ['constraints'], 'yaml', f)

        device = DeviceResources(dev_message)

        allowed_sites = {
            'IOB_X0Y0',
            'IOB_X0Y1',
            'IOB_X0Y2',
            'SLICE_X0Y0',
            'BUFGCTRL_X0Y0',
        }

        model, placement_oracle, placements = make_problem_from_device(
            device, allowed_sites)

        solver = model.build_sat(placements, cells, placement_oracle)
        clauses = solver.prepare_for_sat()

        with Solver() as sat:
            for clause in clauses:
                sat.add_clause(clause)

            solved = sat.solve()
            self.assertTrue(solved)
Ejemplo n.º 14
0
    def setUp(self):
        schema = get_schema(os.environ['INTERCHANGE_SCHEMA_PATH'], 'device',
                            'Device.Constraints')
        path = os.path.join(__dir__, 'data', 'series7_constraints.yaml')
        with open(path, 'rb') as f:
            constraints = read_format(schema, 'yaml', f)

        self.model = Constraints()
        self.model.read_constraints(constraints)

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])
        phys_netlist = example_physical_netlist()
        with open(
                os.path.join(os.environ['DEVICE_RESOURCE_PATH'],
                             phys_netlist.part + '.device'), 'rb') as f:
            device = interchange.read_device_resources(f)

        self.placement_oracle = PlacementOracle()
        self.placement_oracle.add_sites_from_device(device)
Ejemplo n.º 15
0
    def test_check_routing_tree_and_stitch_segments(self):
        phys_netlist = example_physical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])

        with open(
                os.path.join(os.environ['DEVICE_RESOURCE_PATH'],
                             phys_netlist.part + '.device'), 'rb') as f:
            device_resources = interchange.read_device_resources(f)

        phys_netlist.check_physical_nets(device_resources)
        before_stitch = phys_netlist.get_normalized_tuple_tree(
            device_resources)
        phys_netlist.stitch_physical_nets(device_resources)
        after_stitch = phys_netlist.get_normalized_tuple_tree(device_resources)
        phys_netlist.stitch_physical_nets(device_resources, flatten=True)
        after_stitch_from_flat = phys_netlist.get_normalized_tuple_tree(
            device_resources)

        self.assertEqual(len(before_stitch), len(after_stitch))
        self.assertEqual(len(before_stitch), len(after_stitch_from_flat))

        bad_nets = set()
        for net in before_stitch:
            if before_stitch[net] != after_stitch[net]:
                bad_nets.add(net)
                print(net)
                pprint.pprint(before_stitch[net])
                pprint.pprint(after_stitch[net])

            if before_stitch[net] != after_stitch_from_flat[net]:
                bad_nets.add(net)
                print(net)
                pprint.pprint(before_stitch[net])
                pprint.pprint(after_stitch_from_flat[net])

        self.assertEqual(set(), bad_nets)
Ejemplo n.º 16
0
    def test_patch_series7_constraints(self):
        phys_netlist = example_physical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])

        with open(
                os.path.join(os.environ['DEVICE_RESOURCE_PATH'],
                             phys_netlist.part + '.device'), 'rb') as f:
            dev_message = interchange.read_device_resources_raw(f)

        dev_message = dev_message.as_builder()

        path = os.path.join(__dir__, 'data', 'series7_constraints.yaml')
        with open(path, 'rb') as f:
            patch_capnp(dev_message, ['constraints'], 'yaml', f)

        schema = get_schema(os.environ['INTERCHANGE_SCHEMA_PATH'], 'device',
                            'Device.Constraints')
        with open(path, 'rb') as f:
            series7 = read_format(schema, 'yaml', f)

        compare_capnp(self, series7, dev_message.constraints)
Ejemplo n.º 17
0
    def test_physical_netlist(self):
        phys_netlist = example_physical_netlist()

        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])

        with tempfile.NamedTemporaryFile('w+b') as f:
            netlist_capnp = phys_netlist.convert_to_capnp(interchange)
            write_capnp_file(netlist_capnp, f)
            f.seek(0)
            read_phys_netlist = PhysicalNetlist.read_from_capnp(f, interchange)

        self.assertEqual(len(phys_netlist.placements),
                         len(read_phys_netlist.placements))
Ejemplo n.º 18
0
def main():
    parser = argparse.ArgumentParser(description=__doc__)

    parser.add_argument('--schema_dir', required=True)
    parser.add_argument('--device', required=True)
    parser.add_argument('--top', required=True)
    parser.add_argument('--verbose', action='store_true')
    parser.add_argument(
        '--library',
        default='work',
        help='Library to put non-primitive elements')
    parser.add_argument('yosys_json')
    parser.add_argument('netlist')

    args = parser.parse_args()

    with open(args.yosys_json) as f:
        yosys_json = json.load(f)

    assert 'modules' in yosys_json, yosys_json.keys()

    if args.top not in yosys_json['modules']:
        raise RuntimeError(
            'Could not find top module in yosys modules: {}'.format(', '.join(
                yosys_json['modules'].keys())))

    interchange = Interchange(args.schema_dir)

    with open(args.device, 'rb') as f:
        device = interchange.read_device_resources(f)

    netlist = convert_yosys_json(device, yosys_json, args.top, args.library,
                                 args.verbose)
    netlist_capnp = netlist.convert_to_capnp(interchange)

    with open(args.netlist, 'wb') as f:
        write_capnp_file(netlist_capnp, f)
Ejemplo n.º 19
0
    def test_capnp_modes(self):
        logical_netlist = example_logical_netlist()
        interchange = Interchange(
            schema_directory=os.environ['INTERCHANGE_SCHEMA_PATH'])

        for compression_format in [
                CompressionFormat.UNCOMPRESSED, CompressionFormat.GZIP
        ]:
            for packed in [True, False]:
                with tempfile.NamedTemporaryFile('w+b') as f:
                    netlist_capnp = logical_netlist.convert_to_capnp(
                        interchange)
                    write_capnp_file(netlist_capnp,
                                     f,
                                     compression_format=compression_format,
                                     is_packed=packed)
                    f.seek(0)
                    _ = LogicalNetlist.read_from_capnp(
                        f,
                        interchange,
                        compression_format=compression_format,
                        is_packed=packed)
Ejemplo n.º 20
0
def main():

    parser = argparse.ArgumentParser(description="Generates testarch FPGA")
    parser.add_argument("--schema-dir",
                        required=True,
                        help="Path to FPGA interchange capnp schema files")
    parser.add_argument("--out-file",
                        default="test_arch.device",
                        help="Output file name")
    parser.add_argument("--package", default="TESTPKG", help="Package name")
    parser.add_argument(
        "--no-ffmux",
        action="store_true",
        help=
        "Do not add the mux that selects FF input forcing it to require LUT-thru"
    )

    args = parser.parse_args()

    # Run the test architecture generator
    gen = TestArchGenerator(args)
    gen.generate()

    # Initialize the writer (or "serializer")
    interchange = Interchange(args.schema_dir)
    writer = DeviceResourcesCapnp(
        gen.device,
        interchange.device_resources_schema,
        interchange.logical_netlist_schema,
    )

    # Serialize
    device_resources = writer.to_capnp()
    with open(args.out_file, "wb") as fp:
        write_capnp_file(
            device_resources,
            fp)  #, compression_format=CompressionFormat.UNCOMPRESSED)
Ejemplo n.º 21
0
    parser.add_argument("FAMILY", help="The family of the part")
    parser.add_argument("FILE", help="Name of output XDLRC file",
                        nargs='?', default="")
    parser.add_argument("-x", "--extra", help="Generate XDLRC+ file",
                        action="store_true")
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        "-t", "--tile", help="Generate XDLRC for a single tile")
    group.add_argument("-p", "--prim-defs",
                       help="Generate XDLRC for Primitive_Defs only", action="store_true")
    return parser.parse_args()


if __name__ == "__main__":
    args = argparse_setup()

    device_schema = Interchange(args.SCHEMA).device_resources_schema.Device
    device = XDLRC(read_capnp_file(device_schema, args.DEVICE),
                   args.FILE, "artix7", "csg324")

    if args.tile:
        device.generate_tile(args.tile)
        device.close_file()
    elif args.prim_defs:
        device.generate_prim_defs()
        device.close_file()
    elif args.extra:
        device.generate_XDLRC_PLUS()
    else:
        device.generate_XDLRC()
Ejemplo n.º 22
0
def output_interchange(top, capnp_folder, part, f_logical, f_physical, f_xdc):
    """ Output FPGA interchange from top level Module class object.

    top (Module) - Top level module.
    capnp_folder (str) - Path to the interchange capnp folder
    part (str) - Part for physical netlist.
    f_logical (file-like) - File to output logical_netlist.Netlist.
    f_physical (file-like) - File to output physical_netlist.PhysNetlist.

    """
    interchange = Interchange(capnp_folder)

    hdi_primitives = Library('hdi_primitives')
    work = Library('work')
    libraries = {hdi_primitives.name: hdi_primitives, work.name: work}

    top_cell = Cell(top.name)

    # Create source cells for constant nets.  They are required to have some
    # name, so give them one.
    #
    # TODO: Iterate net names on this?  This feels wrong/weird.  Need to
    # handle net name collisions?
    constant_nets = {
        0: "GLOBAL_LOGIC0",
        1: "GLOBAL_LOGIC1",
    }

    top_cell.add_cell_instance(name='VCC', cell_name="VCC")
    top_cell.add_net(constant_nets[1])
    top_cell.connect_net_to_instance(
        net_name=constant_nets[1], instance_name='VCC', port="P")

    top_cell.add_cell_instance(name='GND', cell_name="GND")
    top_cell.add_net(constant_nets[0])
    top_cell.connect_net_to_instance(
        net_name=constant_nets[0], instance_name='GND', port="G")

    # Parse top level port names, and convert to bussed ports as needed.
    create_top_level_ports(top_cell, top, top.root_in, Direction.Input)
    create_top_level_ports(top_cell, top, top.root_out, Direction.Output)
    create_top_level_ports(top_cell, top, top.root_inout, Direction.Inout)

    for wire, width in make_bus(top.wires):
        wire = unescape_verilog_name(wire)
        if width is None:
            top_cell.add_net(name=wire)
        else:
            for idx in range(width + 1):
                top_cell.add_net(name='{}[{}]'.format(wire, idx))

    # Update/create wire_name_net_map from the BELs.
    for site in top.sites:
        for bel in site.bels:
            bel.make_net_map(top=top, net_map=top.wire_name_net_map)

    for sink_wire, source_wire in top.wire_assigns.yield_wires():
        net_name = flatten_wires(source_wire, top.wire_assigns,
                                 top.wire_name_net_map)
        if sink_wire in top.wire_name_net_map:
            assert top.wire_name_net_map[sink_wire] == net_name
        else:
            top.wire_name_net_map[sink_wire] = net_name

    # Create a list of each primative instances to later build up a primative
    # model library.
    hdi_primitives_cells = {}

    # Create cells instances from each bel in the design.
    for site in top.sites:
        for bel in sorted(site.bels, key=lambda bel: bel.priority):
            bel.output_interchange(
                top_cell=top_cell,
                top=top,
                net_map=top.wire_name_net_map,
                constant_nets=constant_nets,
            )

            if bel.parent_cell is not None:
                continue

            if bel.module not in hdi_primitives_cells:
                hdi_primitives_cells[bel.module] = []

            hdi_primitives_cells[bel.module].append(bel)

    # Add top level cell to the work cell library.
    work.add_cell(top_cell)

    # Construct library cells based on data from top module.
    for cellname in hdi_primitives_cells:
        instances = hdi_primitives_cells[cellname]

        cell = Cell(cellname)

        ports = {}
        for instance in instances:
            _, connections, port_is_output = instance.create_connections(top)

            for port in connections:
                if port_is_output[port]:
                    # The current model doesn't handle IO at all, so add
                    # special cases for IO ports in the library.
                    if cellname.startswith('IOBUF') and port == "IO":
                        direction = Direction.Inout
                    else:
                        direction = Direction.Output
                else:
                    direction = Direction.Input

                width = connections[port].bus_width()
                if port in instance.port_width:
                    if width is not None:
                        assert width <= instance.port_width[port], port

                    width = instance.port_width[port]

                if port in ports:
                    port_dir, port_width = ports[port]
                    assert port_dir == direction, (port, direction, port_dir,
                                                   port_width)
                    if width is not None:
                        assert port_width <= width

                        if width > port_width:
                            ports[port] = (direction, width)
                    else:
                        assert port_width is None
                else:
                    ports[port] = (direction, width)

            # Add instances of unconnected ports (as needed).
            for port, direction in instance.port_direction.items():
                width = instance.port_width[port]

                if direction == "output":
                    direction = Direction.Output
                elif direction == "inout":
                    direction = Direction.Inout
                else:
                    assert direction == "input", direction
                    direction = Direction.Input

                if port in ports:
                    assert (direction, width) == ports[port]
                else:
                    ports[port] = (direction, width)

        for port, (direction, width) in ports.items():

            if width is not None:
                cell.add_bus_port(port, direction, start=width - 1, end=0)
            else:
                cell.add_port(port, direction)

        hdi_primitives.add_cell(cell)

    # Make sure VCC and GND primatives are in the library.
    if "VCC" not in hdi_primitives.cells:
        cell = Cell("VCC")
        cell.add_port("P", Direction.Output)

        hdi_primitives.add_cell(cell)

    if "GND" not in hdi_primitives.cells:
        cell = Cell("GND")
        cell.add_port("G", Direction.Output)

        hdi_primitives.add_cell(cell)

    # Logical netlist is complete, output to file now!
    logical_netlist = LogicalNetlist(
        name=top.name,
        property_map={},
        top_instance_name=top.name,
        top_instance=CellInstance(
            cell_name=top.name, view='netlist', property_map={}),
        libraries=libraries,
    ).convert_to_capnp(interchange)
    write_capnp_file(logical_netlist, f_logical)

    physical_netlist = PhysicalNetlist(part=part)

    site_type_pins = {}

    # Convert sites and bels into placement directives and physical nets.
    net_stubs = {}
    sub_cell_nets = {}
    for site in top.sites:
        physical_netlist.add_site_instance(site.site.name, site.site_type())

        for bel in site.bels:
            if bel.site is None or (bel.bel is None
                                    and len(bel.physical_bels) == 0):
                continue

            cell_instance = unescape_verilog_name(bel.get_cell(top))

            # bel.physical_bels is used to represent a transformation that
            # happens from the library cell (e.g. LUT6_2) into lower
            # primatives (LUT6_2 -> (LUT6, LUT5)).
            #
            # Rather than implement generic transformation support, for now
            # models implement the transformation by adding physical bels to
            # generate the correct placement constraints.
            #
            # TODO: Revisit this in the future?
            if len(bel.physical_bels) == 0:
                # Straight forward case, 1 logical Cell -> 1 physical Bel
                placement = Placement(
                    cell_type=bel.module,
                    cell_name=cell_instance,
                    site=bel.site,
                    bel=bel.bel,
                )

                for (bel_name,
                     bel_pin), cell_pin in bel.bel_pins_to_cell_pins.items():
                    placement.add_bel_pin_to_cell_pin(
                        bel_pin=bel_pin,
                        cell_pin=cell_pin,
                        bel=bel_name,
                    )

                physical_netlist.placements.append(placement)
            else:
                # Transformation cases, create a placement constraint for
                # each bel in the physical_bels list.
                #
                # These represent a cell within the primative, hence the "/"
                # when constructing the cell name.
                for phys_bel in bel.physical_bels:
                    placement = Placement(
                        cell_type=phys_bel.module,
                        cell_name=cell_instance + '/' + phys_bel.name,
                        site=bel.site,
                        bel=phys_bel.bel,
                    )

                    for (bel_name, bel_pin
                         ), cell_pin in phys_bel.bel_pins_to_cell_pins.items():
                        placement.add_bel_pin_to_cell_pin(
                            bel_pin=bel_pin,
                            cell_pin=cell_pin,
                            bel=bel_name,
                        )

                    physical_netlist.placements.append(placement)

        # Convert site routing to PhysicalNetlist objects (PhysicalBelPin,
        # PhysicalSitePin, PhysicalSitePip).
        #
        # Note: Calling output_site_routing must be done before
        # output_interchange_nets to ensure that Bel.final_net_names gets
        # populated, as that is computed during Site.output_site_routing.
        new_nets = site.output_site_routing(
            top=top,
            parent_cell=top_cell,
            net_map=top.wire_name_net_map,
            constant_nets=constant_nets,
            sub_cell_nets=sub_cell_nets)

        for site_pin, site_type_pin in site.site_type_pins.items():
            site_type_pins[site.site.name, site_pin] = site_type_pin

        # Extend net stubs with the site routing.
        for net_name in new_nets:
            if net_name not in net_stubs:
                net_stubs[net_name] = []

            net_stubs[net_name].extend(new_nets[net_name])

    # Convert top level routing nets to pip lists and to relevant nets
    for net_name, pips in top.output_interchange_nets(
            constant_nets=constant_nets):
        if net_name not in net_stubs:
            net_stubs[net_name] = []

        for tile, wire0, wire1 in pips:
            # TODO: Better handling of bipips?
            net_stubs[net_name].append(
                PhysicalPipForStitching(
                    tile=tile, wire0=wire0, wire1=wire1, forward=False))

    net_to_type = {}
    for val, net_name in constant_nets.items():
        if val == 0:
            net_to_type[net_name] = PhysicalNetType.Gnd
        else:
            assert val == 1
            net_to_type[net_name] = PhysicalNetType.Vcc

    cursor = top.conn.cursor()
    for net_name in net_stubs:
        sources = []
        stubs = net_stubs[net_name]
        sources, stubs = stitch_stubs(net_stubs[net_name], cursor,
                                      site_type_pins)

        physical_netlist.add_physical_net(
            net_name=sub_cell_nets.get(net_name, net_name),
            sources=sources,
            stubs=stubs,
            net_type=net_to_type.get(net_name, PhysicalNetType.Signal))

    phys_netlist_capnp = physical_netlist.convert_to_capnp(interchange)
    write_capnp_file(phys_netlist_capnp, f_physical)

    for l in top.output_extra_tcl():
        print(l, file=f_xdc)
Ejemplo n.º 23
0
def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--schema_dir', required=True)
    parser.add_argument('--library', default="primitives")
    parser.add_argument('device_in')
    parser.add_argument('yosys_json')
    parser.add_argument('device_out')

    args = parser.parse_args()
    interchange = Interchange(args.schema_dir)
    with open(args.device_in, 'rb') as f:
        device = read_capnp_file(interchange.device_resources_schema.Device, f)

    device = device.as_builder()

    with open(args.yosys_json) as f:
        yosys_json = json.load(f)

    prim_lib = Library(args.library)

    assert 'modules' in yosys_json, yosys_json.keys()
    for module_name, module_data in sorted(yosys_json['modules'].items(),
                                           key=lambda x: x[0]):
        # Library should only contain blackboxes
        assert module_data['attributes'].get('blackbox', 0) or \
            module_data['attributes'].get('whitebox', 0), module_name
        property_map = {}
        if 'attributes' in module_data:
            property_map.update(module_data['attributes'])
        if 'parameters' in module_data:
            property_map.update(module_data['parameters'])
        cell = Cell(module_name, property_map)

        for port_name, port_data in module_data['ports'].items():
            if port_data['direction'] == 'input':
                direction = Direction.Input
            elif port_data['direction'] == 'output':
                direction = Direction.Output
            else:
                assert port_data['direction'] == 'inout'
                direction = Direction.Inout

            property_map = {}
            if 'attributes' in port_data:
                property_map = port_data['attributes']

            offset = port_data.get('offset', 0)
            upto = port_data.get('upto', False)

            if is_bus(port_data['bits'], offset, upto):
                end = offset
                start = offset + len(port_data['bits']) - 1

                if upto:
                    start, end = end, start

                cell.add_bus_port(name=port_name,
                                  direction=direction,
                                  start=start,
                                  end=end,
                                  property_map=property_map)
            else:
                cell.add_port(name=port_name,
                              direction=direction,
                              property_map=property_map)
        prim_lib.add_cell(cell)

    libraries = {}
    libraries[args.library] = prim_lib
    # Create the netlist
    netlist = LogicalNetlist(name=args.library,
                             property_map={},
                             top_instance_name=None,
                             top_instance=None,
                             libraries=libraries)

    str_list = [s for s in device.strList]

    netlist_capnp = netlist.convert_to_capnp(interchange,
                                             indexed_strings=str_list)

    # Patch device
    device.primLibs = netlist_capnp

    if len(device.strList) != len(str_list):
        # At least 1 string was added to the list, update the strList.
        device.init('strList', len(str_list))

        for idx, s in enumerate(str_list):
            device.strList[idx] = s

    # Save patched device
    with open(args.device_out, 'wb') as f:
        write_capnp_file(device, f)
Ejemplo n.º 24
0
def main():
    parser = argparse.ArgumentParser(
        description="Run FPGA constraints placement engine.")
    parser.add_argument('--schema_dir', required=True)
    parser.add_argument('--assumptions',
                        help='Comma seperated list of assumptions to hold')
    parser.add_argument('--verbose', action='store_true')
    parser.add_argument('--allowed_sites', required=True)
    parser.add_argument('--filtered_cells')
    parser.add_argument('device')
    parser.add_argument('netlist')

    args = parser.parse_args()

    interchange = Interchange(args.schema_dir)

    with open(args.device, 'rb') as f:
        device = interchange.read_device_resources(f)

    with open(args.netlist, 'rb') as f:
        netlist = interchange.read_logical_netlist(f)

    allowed_sites = set(args.allowed_sites.split(','))
    filtered_cells = set()
    if args.filtered_cells is not None:
        filtered_cells = set(cell for cell in args.filtered_cells.split(','))

    model, placement_oracle, placements = make_problem_from_device(
        device, allowed_sites)
    cells = create_constraint_cells_from_netlist(netlist, filtered_cells)

    solver = model.build_sat(placements, cells, placement_oracle)

    if args.verbose:
        print()
        print("Preparing solver")
        print()
    clauses = solver.prepare_for_sat()

    if args.verbose:
        print()
        print("Variable names ({} total):".format(len(solver.variable_names)))
        print()
        for variable in solver.variable_names:
            print(variable)

        print()
        print("Clauses:")
        print()
        for clause in solver.abstract_clauses:
            print(clause)

    assumptions = []

    if args.assumptions:
        for assumption in args.assumptions.split(','):
            assumptions.append(solver.get_variable(assumption))

    with Solver() as sat:
        for clause in clauses:
            if args.verbose:
                print(clause)
            sat.add_clause(clause)

        if args.verbose:
            print()
            print("Running SAT:")
            print()
            print("Assumptions:")
            print(assumptions)

        solved = sat.solve(assumptions=assumptions)
        if args.verbose:
            print(sat.time())

        if solved:
            model = sat.get_model()
        else:
            core = sat.get_core()

    if solved:
        if args.verbose:
            print()
            print("Raw Solution:")
            print()
            print(model)

        print("Solution:")
        state_groups_vars, other_vars = solver.decode_solution_model(model)
        assert len(other_vars) == 0

        pprint.pprint(state_groups_vars)
    else:
        print("Unsatifiable!")
        if core is not None:
            print("Core:")
            print(core)
            print("Core variables:")
            for core_index in core:
                print(solver.variable_names[core_index])
        sys.exit(1)
Ejemplo n.º 25
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--schema_dir', required=True)
    parser.add_argument('--output_dir', required=True)
    parser.add_argument('--device', required=True)
    parser.add_argument('--device_config', required=True)
    parser.add_argument(
        '--suffix',
        type=str,
        default=None,
        help="An optional suffix to append to output file names")

    args = parser.parse_args()
    interchange = Interchange(args.schema_dir)

    with open(args.device, 'rb') as f:
        device = interchange.read_device_resources(f)

    with open(args.device_config, 'r') as f:
        device_config = yaml.safe_load(f.read())

    const_ids = Enumerator()

    # ID = 0 is always the empty string!
    assert const_ids.get_index('') == 0

    chip_info = populate_chip_info(device, const_ids, device_config)

    if args.suffix:
        fname = 'chipdb-{}.bba'.format(args.suffix)
    else:
        fname = 'chipdb.bba'

    with open(os.path.join(args.output_dir, fname), 'w') as f:
        bba = BbaWriter(f, const_ids)
        bba.pre("#include \"nextpnr.h\"")
        bba.pre("NEXTPNR_NAMESPACE_BEGIN")
        bba.post("NEXTPNR_NAMESPACE_END")
        bba.push("chipdb_blob")

        root_prefix = 'chip_info'
        bba.ref(root_prefix, root_prefix)
        chip_info.append_bba(bba, root_prefix)

        bba.label(chip_info.strings_label(root_prefix), 'strings_slice')
        bba.ref('strings_data')
        bba.u32(len(const_ids.values) - 1)

        bba.label('strings_data', 'strings')
        for s in const_ids.values[1:]:
            bba.str(s)

        bba.pop()

    bba.check_labels()

    if args.suffix:
        fname = 'constids-{}.txt'.format(args.suffix)
    else:
        fname = 'constids.txt'

    with open(os.path.join(args.output_dir, fname), 'w') as f:
        for s in const_ids.values[1:]:
            print('X({})'.format(s), file=f)