#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Copyright 2020 The SkyWater PDK Authors. # # Use of this source code is governed by the Apache 2.0 # license that can be found in the LICENSE file or at # https://www.apache.org/licenses/LICENSE-2.0 # # SPDX-License-Identifier: Apache-2.0 ''' This is a prototype of cell documentation generation script. ''' import csv import json import os import sys import argparse import pathlib import glob import subprocess import textwrap readme_template ="""\ {header} {headerUL} **{description}** *This is a stub of cell description file* - **Cell name**: {name} - **Type**: {deftype} - **Verilog name**: {verilog_name} - **Library**: {library} - **Inputs**: {inputs} - **Outputs**: {outputs} Symbols ------- .. list-table:: * - .. figure:: {symbol1} - - .. figure:: {symbol2} Schematic --------- .. figure:: {schematic} :align: center GDSII Layouts ------------- """ figure_template =""" .. figure:: {fig} :align: center :width: 50% {name} """ def write_readme(cellpath, define_data): ''' Generates README for a given cell. Args: cellpath - path to a cell [str of pathlib.Path] define_data - cell data from json [dic] ''' netlist_json = os.path.join(cellpath, define_data['file_prefix']+'.json') assert os.path.exists(netlist_json), netlist_json outpath = os.path.join(cellpath, 'README.rst') prefix = define_data['file_prefix'] header = prefix symbol1 = prefix + '.symbol.svg' symbol2 = prefix + '.pp.symbol.svg' schematic = prefix + '.schematic.svg' inputs = [] outputs = [] for p in define_data['ports']: try: if p[0]=='signal' and p[2]=='input': inputs.append(p[1]) if p[0]=='signal' and p[2]=='output': outputs.append(p[1]) except: pass gdssvg = [] svglist = list(pathlib.Path(cellpath).glob('*.svg')) for s in svglist: gdsfile = pathlib.Path(os.path.join(cellpath, s.stem +'.gds')) if gdsfile.is_file(): gdssvg.append(s) with open(outpath, 'w') as f: f.write (readme_template.format ( header = header, headerUL = '=' * len(header), description = define_data['description'].rstrip('.'), name = ':cell:`' + prefix +'`', deftype = define_data['type'], verilog_name = define_data['verilog_name'], library = define_data['library'], inputs = f'{len(inputs)} (' + ', '.join(inputs) + ')', outputs = f'{len(outputs)} (' + ', '.join(outputs) + ')', symbol1 = symbol1, symbol2 = symbol2, schematic = schematic, )) for gs in sorted(gdssvg): f.write (figure_template.format ( fig = gs.name, name = gs.stem )) def process(cellpath): ''' Processes cell indicated by path. Opens cell definiton and calls further processing Args: cellpath - path to a cell [str of pathlib.Path] ''' print() print(cellpath) define_json = os.path.join(cellpath, 'definition.json') if not os.path.exists(define_json): print("No definition.json in", cellpath) assert os.path.exists(define_json), define_json define_data = json.load(open(define_json)) if define_data['type'] == 'cell': write_readme(cellpath, define_data) return def main(): ''' Generates README.rst for cell.''' prereq_txt = '' output_txt = 'output:\n generates README.rst' allcellpath = '../../../libraries/*/latest/cells/*' parser = argparse.ArgumentParser( description = main.__doc__, epilog = prereq_txt +'\n\n'+ output_txt, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument( "--all_libs", help="process all cells in "+allcellpath, action="store_true") parser.add_argument( "cell_dir", help="path to the cell directory", type=pathlib.Path, nargs="*") args = parser.parse_args() if args.all_libs: path = pathlib.Path(allcellpath).expanduser() parts = path.parts[1:] if path.is_absolute() else path.parts paths = pathlib.Path(path.root).glob(str(pathlib.Path("").joinpath(*parts))) args.cell_dir = list(paths) cell_dirs = [d.resolve() for d in args.cell_dir if d.is_dir()] errors = 0 for d in cell_dirs: try: process(d) except KeyboardInterrupt: sys.exit(1) except (AssertionError, FileNotFoundError, ChildProcessError) as ex: print (f'Error: {type(ex).__name__}') print (f'{ex.args}') errors +=1 print (f'\n{len(cell_dirs)} files processed, {errors} errors.') return 0 if errors else 1 if __name__ == "__main__": sys.exit(main())