194 lines
4.9 KiB
Python
Executable File
194 lines
4.9 KiB
Python
Executable File
#!/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())
|
|
|