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)
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())
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'))
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)
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)
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)
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)
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)
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)
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)
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))
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)
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)
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)
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()
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)
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)
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)
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)