| #!/usr/bin/env python3 | |
| """ | |
| Project Trellis Master HTML Generation Script | |
| Usage: | |
| html_all.py <output_folder> | |
| """ | |
| import os, sys, time | |
| from os import path | |
| from string import Template | |
| import argparse | |
| import database | |
| import html_tilegrid | |
| import html_bits | |
| import fuzzloops | |
| import pytrellis | |
| import cell_html | |
| import timing_dbs | |
| import interconnect_html | |
| trellis_docs_index = """ | |
| <html> | |
| <head> | |
| <title>Project Trellis HTML Documentation</title> | |
| </head> | |
| <body> | |
| <h1>Project Trellis HTML Documentation</h1> | |
| <p>Project Trellis is a project to document the ECP5 bitstream and internal architecture.</p> | |
| <p>This repository contains HTML documentation automatically generated from the | |
| <a href="https://github.com/SymbiFlow/prjtrellis">Project Trellis</a> database. The equivalent | |
| machine-readable data is located in <a href="https://github.com/SymbiFlow/prjtrellis-db">prjtrellis-db.<a/> | |
| Data generated includes tilemap data and bitstream data for many tile types. Click on any tile to see its bitstream | |
| documentation. | |
| </p> | |
| <p>More human-readable documentation on the ECP5 architecture and the Project Trellis methodology can be found | |
| on the <a href="http://prjtrellis.readthedocs.io/en/latest/">Read the Docs</a> site.</p> | |
| <p>This HTML documentation was generated at ${datetime} from prjtrellis-db commit | |
| <a href="https://github.com/SymbiFlow/prjtrellis-db/tree/${commit}">${commit}</a>.</p> | |
| <hr/> | |
| $docs_toc | |
| <hr/> | |
| <p>Licensed under a very permissive <a href="COPYING">CC0 1.0 Universal</a> license.</p> | |
| </body> | |
| </html> | |
| """ | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument('fld', type=str, | |
| help="output folder") | |
| def generate_device_docs(family, device, folder): | |
| html_tilegrid.main(["html_tilegrid", family, device, path.join(folder, "index.html")]) | |
| def generate_tile_docs(family, device, tile, folder): | |
| html_bits.main(["html_bits", family, device, tile, path.join(folder, "{}.html".format(tile))]) | |
| def get_device_tiles(family, devices): | |
| all_tiles = set() | |
| fd_tiles = {} | |
| for dev, devdata in sorted(devices.items()): | |
| if devdata["fuzz"]: | |
| fd_tiles[family, dev] = [] | |
| c = pytrellis.Chip(dev) | |
| for tile in c.get_all_tiles(): | |
| tt = tile.info.type | |
| if tt not in all_tiles: | |
| all_tiles.add(tt) | |
| fd_tiles[family, dev].append(tt) | |
| return fd_tiles | |
| def main(argv): | |
| args = parser.parse_args(argv[1:]) | |
| if not path.exists(args.fld): | |
| os.mkdir(args.fld) | |
| commit_hash = database.get_db_commit() | |
| build_dt = time.strftime('%Y-%m-%d %H:%M:%S') | |
| docs_toc = "" | |
| pytrellis.load_database(database.get_db_root()) | |
| for fam, fam_data in sorted(database.get_devices()["families"].items()): | |
| if fam == "MachXO2": | |
| continue | |
| fdir = path.join(args.fld, fam) | |
| if not path.exists(fdir): | |
| os.mkdir(fdir) | |
| thdir = path.join(fdir, "tilehtml") | |
| if not path.exists(thdir): | |
| os.mkdir(thdir) | |
| docs_toc += "<h3>{} Family</h3>".format(fam) | |
| docs_toc += "<h4>Bitstream Documentation</h4>" | |
| docs_toc += "<ul>" | |
| tiles = get_device_tiles(fam, fam_data["devices"]) | |
| for dev, devdata in sorted(fam_data["devices"].items()): | |
| if devdata["fuzz"]: | |
| ddir = path.join(fdir, dev) | |
| if not path.exists(ddir): | |
| os.mkdir(ddir) | |
| print("********* Generating documentation for device {}".format(dev)) | |
| generate_device_docs(fam, dev, ddir) | |
| if (fam, dev) in tiles: | |
| for tile in tiles[fam, dev]: | |
| print("*** Generating documentation for tile {}".format(tile)) | |
| generate_tile_docs(fam, dev, tile, thdir) | |
| docs_toc += '<li><a href="{}">{} Documentation</a></li>'.format( | |
| '{}/{}/index.html'.format(fam, dev), | |
| dev | |
| ) | |
| docs_toc += "</ul>" | |
| docs_toc += "<h4>Cell Timing Documentation</h4>" | |
| docs_toc += "<ul>" | |
| for spgrade in ["6", "7", "8", "8_5G"]: | |
| tdir = path.join(fdir, "timing") | |
| if not path.exists(tdir): | |
| os.mkdir(tdir) | |
| docs_toc += '<li><a href="{}">Speed Grade -{}</a></li>'.format( | |
| '{}/timing/cell_timing_{}.html'.format(fam, spgrade), | |
| spgrade | |
| ) | |
| cell_html.make_cell_timing_html(timing_dbs.cells_db_path(fam, spgrade), fam, spgrade, | |
| path.join(tdir, 'cell_timing_{}.html'.format(spgrade))) | |
| docs_toc += "</ul>" | |
| docs_toc += "<h4>Interconnect Timing Documentation</h4>" | |
| docs_toc += "<ul>" | |
| for spgrade in ["6", "7", "8", "8_5G"]: | |
| tdir = path.join(fdir, "timing") | |
| if not path.exists(tdir): | |
| os.mkdir(tdir) | |
| docs_toc += '<li><a href="{}">Speed Grade -{}</a></li>'.format( | |
| '{}/timing/interconn_timing_{}.html'.format(fam, spgrade), | |
| spgrade | |
| ) | |
| interconnect_html.make_interconn_timing_html(timing_dbs.interconnect_db_path(fam, spgrade), fam, spgrade, | |
| path.join(tdir, 'interconn_timing_{}.html'.format(spgrade))) | |
| docs_toc += "</ul>" | |
| index_html = Template(trellis_docs_index).substitute( | |
| datetime=build_dt, | |
| commit=commit_hash, | |
| docs_toc=docs_toc | |
| ) | |
| with open(path.join(args.fld, "index.html"), 'w') as f: | |
| f.write(index_html) | |
| if __name__ == "__main__": | |
| main(sys.argv) |