mirror of
https://github.com/TinyTapeout/tt-support-tools.git
synced 2026-11-03 04:36:09 +01:00
first pass after splitting configure.py and incorporating sssummarizer
This commit is contained in:
+184
@@ -0,0 +1,184 @@
|
|||||||
|
{
|
||||||
|
"categories" : [
|
||||||
|
"AND",
|
||||||
|
"OR",
|
||||||
|
"NAND",
|
||||||
|
"NOR",
|
||||||
|
"Clock",
|
||||||
|
"Flip Flops",
|
||||||
|
"Multiplexer",
|
||||||
|
"Latch",
|
||||||
|
"Inverter",
|
||||||
|
"Buffer",
|
||||||
|
"Fill",
|
||||||
|
"Tap",
|
||||||
|
"Diode",
|
||||||
|
"Combo Logic",
|
||||||
|
"Misc"
|
||||||
|
],
|
||||||
|
"map" : {
|
||||||
|
"a2111o" : 13,
|
||||||
|
"a2111oi" : 13,
|
||||||
|
"a211o" : 13,
|
||||||
|
"a211oi" : 13,
|
||||||
|
"a21bo" : 13,
|
||||||
|
"a21boi" : 0,
|
||||||
|
"a21o" : 13,
|
||||||
|
"a21oi" : 13,
|
||||||
|
"a221o" : 13,
|
||||||
|
"a221oi" : 13,
|
||||||
|
"a222oi" : 13,
|
||||||
|
"a22o" : 13,
|
||||||
|
"a22oi" : 13,
|
||||||
|
"a2bb2o" : 13,
|
||||||
|
"a2bb2oi" : 13,
|
||||||
|
"a311o" : 13,
|
||||||
|
"a311oi" : 13,
|
||||||
|
"a31o" : 13,
|
||||||
|
"a31oi" : 13,
|
||||||
|
"a32o" : 13,
|
||||||
|
"a32oi" : 13,
|
||||||
|
"a41o" : 13,
|
||||||
|
"a41oi" : 13,
|
||||||
|
"and2" : 0,
|
||||||
|
"and2b" : 13,
|
||||||
|
"and3" : 0,
|
||||||
|
"and3b" : 13,
|
||||||
|
"and4" : 0,
|
||||||
|
"and4b" : 13,
|
||||||
|
"and4bb" : 13,
|
||||||
|
"buf" : 9,
|
||||||
|
"bufbuf" : 9,
|
||||||
|
"bufinv" : 9,
|
||||||
|
"clkbuf" : 9,
|
||||||
|
"clkdlybuf4s15" : 4,
|
||||||
|
"clkdlybuf4s18" : 4,
|
||||||
|
"clkdlybuf4s25" : 4,
|
||||||
|
"clkdlybuf4s50" : 4,
|
||||||
|
"clkinv" : 4,
|
||||||
|
"clkinvlp" : 4,
|
||||||
|
"conb" : 14,
|
||||||
|
"decap" : 10,
|
||||||
|
"dfbbn" : 5,
|
||||||
|
"dfbbp" : 5,
|
||||||
|
"dfrbp" : 5,
|
||||||
|
"dfrtn" : 5,
|
||||||
|
"dfrtp" : 5,
|
||||||
|
"dfsbp" : 5,
|
||||||
|
"dfstp" : 5,
|
||||||
|
"dfxbp" : 5,
|
||||||
|
"dfxtp" : 5,
|
||||||
|
"diode" : 12,
|
||||||
|
"dlclkp" : 4,
|
||||||
|
"dlrbn" : 7,
|
||||||
|
"dlrbp" : 7,
|
||||||
|
"dlrtn" : 7,
|
||||||
|
"dlrtp" : 7,
|
||||||
|
"dlxbn" : 7,
|
||||||
|
"dlxbp" : 7,
|
||||||
|
"dlxtn" : 7,
|
||||||
|
"dlxtp" : 7,
|
||||||
|
"dlygate4sd1" : 14,
|
||||||
|
"dlygate4sd2" : 14,
|
||||||
|
"dlygate4sd3" : 14,
|
||||||
|
"dlymetal6s2s" : 14,
|
||||||
|
"dlymetal6s4s" : 14,
|
||||||
|
"dlymetal6s6s" : 14,
|
||||||
|
"ebufn" : 14,
|
||||||
|
"edfxbp" : 5,
|
||||||
|
"edfxtp" : 5,
|
||||||
|
"einvn" : 14,
|
||||||
|
"einvp" : 11,
|
||||||
|
"fa" : 14,
|
||||||
|
"fah" : 14,
|
||||||
|
"fahcin" : 14,
|
||||||
|
"fahcon" : 14,
|
||||||
|
"fill" : 10,
|
||||||
|
"ha" : 14,
|
||||||
|
"inv" : 8,
|
||||||
|
"lpflow_bleeder" : 14,
|
||||||
|
"lpflow_clkbufkapwr" : 4,
|
||||||
|
"lpflow_clkinvkapwr" : 4,
|
||||||
|
"lpflow_decapkapwr" : 10,
|
||||||
|
"lpflow_inputiso0n" : 14,
|
||||||
|
"lpflow_inputiso0p" : 14,
|
||||||
|
"lpflow_inputiso1n" : 14,
|
||||||
|
"lpflow_inputiso1p" : 14,
|
||||||
|
"lpflow_inputisolatch" : 14,
|
||||||
|
"lpflow_isobufsrc" : 14,
|
||||||
|
"lpflow_isobufsrckapwr" : 14,
|
||||||
|
"lpflow_lsbuf_lh_hl_isowell_tap" : 9,
|
||||||
|
"lpflow_lsbuf_lh_isowell" : 9,
|
||||||
|
"lpflow_lsbuf_lh_isowell_tap" : 9,
|
||||||
|
"macro_sparecell" : 14,
|
||||||
|
"maj3" : 14,
|
||||||
|
"mux2" : 6,
|
||||||
|
"mux2i" : 6,
|
||||||
|
"mux4" : 6,
|
||||||
|
"nand2" : 2,
|
||||||
|
"nand2b" : 2,
|
||||||
|
"nand3" : 2,
|
||||||
|
"nand3b" : 13,
|
||||||
|
"nand4" : 2,
|
||||||
|
"nand4b" : 13,
|
||||||
|
"nand4bb" : 13,
|
||||||
|
"nor2" : 3,
|
||||||
|
"nor2b" : 13,
|
||||||
|
"nor3" : 3,
|
||||||
|
"nor3b" : 13,
|
||||||
|
"nor4" : 3,
|
||||||
|
"nor4b" : 13,
|
||||||
|
"nor4bb" : 13,
|
||||||
|
"o2111a" : 13,
|
||||||
|
"o2111ai" : 13,
|
||||||
|
"o211a" : 13,
|
||||||
|
"o211ai" : 13,
|
||||||
|
"o21a" : 13,
|
||||||
|
"o21ai" : 13,
|
||||||
|
"o21ba" : 13,
|
||||||
|
"o21bai" : 13,
|
||||||
|
"o221a" : 13,
|
||||||
|
"o221ai" : 13,
|
||||||
|
"o22a" : 13,
|
||||||
|
"o22ai" : 13,
|
||||||
|
"o2bb2a" : 13,
|
||||||
|
"o2bb2ai" : 13,
|
||||||
|
"o311a" : 13,
|
||||||
|
"o311ai" : 13,
|
||||||
|
"o31a" : 13,
|
||||||
|
"o31ai" : 13,
|
||||||
|
"o32a" : 13,
|
||||||
|
"o32ai" : 13,
|
||||||
|
"o41a" : 13,
|
||||||
|
"o41ai" : 13,
|
||||||
|
"or2" : 1,
|
||||||
|
"or2b" : 13,
|
||||||
|
"or3" : 1,
|
||||||
|
"or3b" : 13,
|
||||||
|
"or4" : 1,
|
||||||
|
"or4b" : 13,
|
||||||
|
"or4bb" : 13,
|
||||||
|
"probe_p" : 14,
|
||||||
|
"probec_p" : 14,
|
||||||
|
"sdfbbn" : 5,
|
||||||
|
"sdfbbp" : 5,
|
||||||
|
"sdfrbp" : 5,
|
||||||
|
"sdfrtn" : 5,
|
||||||
|
"sdfrtp" : 5,
|
||||||
|
"sdfsbp" : 5,
|
||||||
|
"sdfstp" : 5,
|
||||||
|
"sdfxbp" : 5,
|
||||||
|
"sdfxtp" : 5,
|
||||||
|
"sdlclkp" : 4,
|
||||||
|
"sedfxbp" : 5,
|
||||||
|
"sedfxtp" : 5,
|
||||||
|
"tap" : 11,
|
||||||
|
"tapvgnd" : 11,
|
||||||
|
"tapvgnd2" : 11,
|
||||||
|
"tapvpwrvgnd" : 11,
|
||||||
|
"xnor2" : 3,
|
||||||
|
"xnor3" : 3,
|
||||||
|
"xor2" : 1,
|
||||||
|
"xor3" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
documentclass: scrartcl
|
||||||
|
geometry: margin=2cm
|
||||||
|
fontsize: 14pt
|
||||||
|
mainfont: Latin Modern Sans
|
||||||
|
header-includes:
|
||||||
|
- \hypersetup{colorlinks=false,
|
||||||
|
allbordercolors={0 0 0},
|
||||||
|
pdfborderstyle={/S/U/W 1}}
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
## {title}
|
||||||
|
|
||||||
|
{picture_link}
|
||||||
|
|
||||||
|
* Author: {author}
|
||||||
|
* Description: {description}
|
||||||
|
* [Extra docs]({doc_link})
|
||||||
|
* Clock: {clock_hz} Hz
|
||||||
|
* External hardware: {external_hw}
|
||||||
|
|
||||||
|
### How it works
|
||||||
|
|
||||||
|
{how_it_works}
|
||||||
|
|
||||||
|
### How to test
|
||||||
|
|
||||||
|
{how_to_test}
|
||||||
|
|
||||||
|
### IO
|
||||||
|
|
||||||
|
| # | Input | Output |
|
||||||
|
|---|--------------|--------------|
|
||||||
|
| 0 | {inputs[0]} | {outputs[0]} |
|
||||||
|
| 1 | {inputs[1]} | {outputs[1]} |
|
||||||
|
| 2 | {inputs[2]} | {outputs[2]} |
|
||||||
|
| 3 | {inputs[3]} | {outputs[3]} |
|
||||||
|
| 4 | {inputs[4]} | {outputs[4]} |
|
||||||
|
| 5 | {inputs[5]} | {outputs[5]} |
|
||||||
|
| 6 | {inputs[6]} | {outputs[6]} |
|
||||||
|
| 7 | {inputs[7]} | {outputs[7]} |
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# documentation
|
||||||
|
def check_yaml_docs(yaml):
|
||||||
|
logging.info("checking docs")
|
||||||
|
for key in ['author', 'title', 'description', 'how_it_works', 'how_to_test', 'language']:
|
||||||
|
if key not in yaml['documentation']:
|
||||||
|
logging.error("missing key {} in documentation".format(key))
|
||||||
|
exit(1)
|
||||||
|
if yaml['documentation'][key] == "":
|
||||||
|
logging.error("missing value for {} in documentation".format(key))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# if provided, check discord handle is valid
|
||||||
|
if len(yaml['documentation']['discord']):
|
||||||
|
parts = yaml['documentation']['discord'].split('#')
|
||||||
|
if len(parts) != 2 or len(parts[0]) == 0 or not re.match('^[0-9]{4}$', parts[1]):
|
||||||
|
logging.error('Invalid format for discord username')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def create_pdf(yaml):
|
||||||
|
yaml = yaml['documentation']
|
||||||
|
logging.info("creating pdf")
|
||||||
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
with open(os.path.join(script_dir, "docs/project_header.md")) as fh:
|
||||||
|
doc_header = fh.read()
|
||||||
|
with open(os.path.join(script_dir, "docs/project_preview.md")) as fh:
|
||||||
|
doc_template = fh.read()
|
||||||
|
|
||||||
|
with open('datasheet.md', 'w') as fh:
|
||||||
|
fh.write(doc_header)
|
||||||
|
# handle pictures
|
||||||
|
yaml['picture_link'] = ''
|
||||||
|
if yaml['picture']:
|
||||||
|
# skip SVG for now, not supported by pandoc
|
||||||
|
picture_name = yaml['picture']
|
||||||
|
if 'svg' not in picture_name:
|
||||||
|
yaml['picture_link'] = ''.format(picture_name)
|
||||||
|
else:
|
||||||
|
logging.warning("svg not supported")
|
||||||
|
|
||||||
|
# now build the doc & print it
|
||||||
|
try:
|
||||||
|
doc = doc_template.format(**yaml)
|
||||||
|
fh.write(doc)
|
||||||
|
fh.write("\n\pagebreak\n")
|
||||||
|
except IndexError:
|
||||||
|
logging.warning("missing pins in info.yaml, skipping")
|
||||||
|
|
||||||
|
pdf_cmd = 'pandoc --pdf-engine=xelatex -i datasheet.md -o datasheet.pdf'
|
||||||
|
logging.info(pdf_cmd)
|
||||||
|
p = subprocess.run(pdf_cmd, shell=True)
|
||||||
|
if p.returncode != 0:
|
||||||
|
logging.error("pdf command failed")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
flake8 --ignore E203,E123,E501,E221,E401,W605 documentation.py project.py tt_tool.py reports.py
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
import yaml
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def load_yaml(args):
|
||||||
|
with open(args.yaml, "r") as stream:
|
||||||
|
return (yaml.safe_load(stream))
|
||||||
|
|
||||||
|
|
||||||
|
def create_user_config(yaml):
|
||||||
|
logging.info("creating include file")
|
||||||
|
sources = get_project_source(yaml)
|
||||||
|
top_module = get_top_module(yaml)
|
||||||
|
|
||||||
|
if top_module == 'top':
|
||||||
|
logging.error("top module cannot be called top - prepend your repo name to make it unique")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
filename = 'user_config.tcl'
|
||||||
|
with open(os.path.join('src', filename), 'w') as fh:
|
||||||
|
fh.write("set ::env(DESIGN_NAME) {}\n".format(top_module))
|
||||||
|
fh.write('set ::env(VERILOG_FILES) "\\\n')
|
||||||
|
for line, source in enumerate(sources):
|
||||||
|
fh.write(" $::env(DESIGN_DIR)/" + source)
|
||||||
|
if line != len(sources) - 1:
|
||||||
|
fh.write(' \\\n')
|
||||||
|
fh.write('"\n')
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_file(url, filename):
|
||||||
|
logging.info("trying to download {}".format(url))
|
||||||
|
r = requests.get(url)
|
||||||
|
if r.status_code != 200:
|
||||||
|
logging.warning("couldn't download {}".format(url))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
with open(filename, 'wb') as fh:
|
||||||
|
logging.info("written to {}".format(filename))
|
||||||
|
fh.write(r.content)
|
||||||
|
|
||||||
|
|
||||||
|
def get_project_source(yaml):
|
||||||
|
# wokwi_id must be an int or 0
|
||||||
|
try:
|
||||||
|
wokwi_id = int(yaml['project']['wokwi_id'])
|
||||||
|
except ValueError:
|
||||||
|
logging.error("wokwi id must be an integer")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# it's a wokwi project
|
||||||
|
if wokwi_id != 0:
|
||||||
|
url = "https://wokwi.com/api/projects/{}/verilog".format(wokwi_id)
|
||||||
|
src_file = "user_module_{}.v".format(wokwi_id)
|
||||||
|
fetch_file(url, os.path.join("src", src_file))
|
||||||
|
|
||||||
|
# also fetch the wokwi diagram
|
||||||
|
url = "https://wokwi.com/api/projects/{}/diagram.json".format(wokwi_id)
|
||||||
|
diagram_file = "wokwi_diagram.json"
|
||||||
|
fetch_file(url, os.path.join("src", diagram_file))
|
||||||
|
|
||||||
|
return [src_file, 'cells.v']
|
||||||
|
|
||||||
|
# else it's HDL, so check source files
|
||||||
|
else:
|
||||||
|
if 'source_files' not in yaml['project']:
|
||||||
|
logging.error("source files must be provided if wokwi_id is set to 0")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
source_files = yaml['project']['source_files']
|
||||||
|
if source_files is None:
|
||||||
|
logging.error("must be more than 1 source file")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if len(source_files) == 0:
|
||||||
|
logging.error("must be more than 1 source file")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if 'top_module' not in yaml['project']:
|
||||||
|
logging.error("must provide a top module name")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
for filename in source_files:
|
||||||
|
if not os.path.exists(os.path.join('src', filename)):
|
||||||
|
logging.error(f"{filename} doesn't exist in the repo")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
return source_files
|
||||||
|
|
||||||
|
|
||||||
|
def get_top_module(yaml):
|
||||||
|
wokwi_id = int(yaml['project']['wokwi_id'])
|
||||||
|
if wokwi_id != 0:
|
||||||
|
return "user_module_{}".format(wokwi_id)
|
||||||
|
else:
|
||||||
|
return yaml['project']['top_module']
|
||||||
Executable
+116
@@ -0,0 +1,116 @@
|
|||||||
|
import os
|
||||||
|
import csv
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import glob
|
||||||
|
|
||||||
|
# can't find a google version
|
||||||
|
CELL_URL = 'https://antmicro-skywater-pdk-docs.readthedocs.io/en/test-submodules-in-rtd/contents/libraries/sky130_fd_sc_ls/cells/'
|
||||||
|
|
||||||
|
|
||||||
|
def print_warnings(args):
|
||||||
|
warnings = []
|
||||||
|
with open(os.path.join(args.run_dir, 'logs/synthesis/1-synthesis.log')) as f:
|
||||||
|
for line in f.readlines():
|
||||||
|
if line.startswith('Warning:'):
|
||||||
|
# bogus warning https://github.com/YosysHQ/yosys/commit/bfacaddca8a2e113e4bc3d6177612ccdba1555c8
|
||||||
|
if 'WIDTHLABEL' not in line:
|
||||||
|
warnings.append(line.strip())
|
||||||
|
if len(warnings):
|
||||||
|
print('# Synthesis warnings')
|
||||||
|
print()
|
||||||
|
for warning in warnings:
|
||||||
|
print(f'* {warning}')
|
||||||
|
|
||||||
|
|
||||||
|
def print_stats(args):
|
||||||
|
with open(os.path.join(args.run_dir, 'reports/metrics.csv')) as f:
|
||||||
|
report = list(csv.DictReader(f))[0]
|
||||||
|
|
||||||
|
print('# Routing stats')
|
||||||
|
print()
|
||||||
|
print('| Utilisation | Wire length (um) |')
|
||||||
|
print('|-------------|------------------|')
|
||||||
|
print('| {} | {} |'.format(report['OpenDP_Util'], report['wire_length']))
|
||||||
|
|
||||||
|
|
||||||
|
# Print the summaries
|
||||||
|
def summarize(args):
|
||||||
|
cell_count = get_cell_count_from_gl(args)
|
||||||
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
with open(os.path.join(script_dir, 'categories.json')) as fh:
|
||||||
|
categories = json.load(fh)
|
||||||
|
with open(os.path.join(script_dir, 'defs.json')) as fh:
|
||||||
|
defs = json.load(fh)
|
||||||
|
|
||||||
|
# print all used cells, sorted by frequency
|
||||||
|
total = 0
|
||||||
|
if args.print_cell_summary:
|
||||||
|
print('# Cell usage')
|
||||||
|
print()
|
||||||
|
print('| Cell Name | Description | Count |')
|
||||||
|
print('|-----------|-------------|-------|')
|
||||||
|
for name, count in sorted(cell_count.items(), key=lambda item: item[1], reverse=True):
|
||||||
|
if count > 0:
|
||||||
|
total += count
|
||||||
|
cell_link = f'{CELL_URL}{name}'
|
||||||
|
print(f'| [{name}]({cell_link}) | {defs[name]["description"]} |{count} |')
|
||||||
|
|
||||||
|
print(f'| | Total | {total} |')
|
||||||
|
|
||||||
|
if args.print_cell_category:
|
||||||
|
by_category = {}
|
||||||
|
for cell_name in cell_count:
|
||||||
|
cat_index = categories['map'][cell_name]
|
||||||
|
cat_name = categories['categories'][cat_index]
|
||||||
|
if cat_name in by_category:
|
||||||
|
by_category[cat_name]['count'] += cell_count[cell_name]
|
||||||
|
by_category[cat_name]['examples'].append(cell_name)
|
||||||
|
else:
|
||||||
|
by_category[cat_name] = {'count' : cell_count[cell_name], 'examples' : [cell_name]}
|
||||||
|
|
||||||
|
print('# Cell usage by Category')
|
||||||
|
print()
|
||||||
|
print('| Category | Cells | Count |')
|
||||||
|
print('|---------------|----------|-------|')
|
||||||
|
for cat_name, cat_dict in sorted(by_category.items(), key=lambda x: x[1]['count'], reverse=True):
|
||||||
|
cell_links = [f'[{name}]({CELL_URL}{name})' for name in cat_dict['examples']]
|
||||||
|
print(f'|{cat_name} | {" ".join(cell_links)} | {cat_dict["count"]}|')
|
||||||
|
|
||||||
|
|
||||||
|
# Parse the lib, cell and drive strength an OpenLane gate-level Verilog file
|
||||||
|
def get_cell_count_from_gl(args):
|
||||||
|
cell_count = {}
|
||||||
|
total = 0
|
||||||
|
gl_files = glob.glob(os.path.join(args.run_dir, 'results/final/verilog/gl/*.nl.v'))
|
||||||
|
with open(gl_files[0]) as fh:
|
||||||
|
for line in fh.readlines():
|
||||||
|
m = re.search(r'sky130_(\S+)__(\S+)_(\d+)', line)
|
||||||
|
if m is not None:
|
||||||
|
total += 1
|
||||||
|
cell_lib = m.group(1)
|
||||||
|
cell_name = m.group(2)
|
||||||
|
cell_drive = m.group(3)
|
||||||
|
assert cell_lib in ['fd_sc_hd', 'ef_sc_hd']
|
||||||
|
assert int(cell_drive) > 0
|
||||||
|
try:
|
||||||
|
cell_count[cell_name] += 1
|
||||||
|
except KeyError:
|
||||||
|
cell_count[cell_name] = 1
|
||||||
|
return (cell_count)
|
||||||
|
|
||||||
|
|
||||||
|
# Load all the json defs and combine into one big dict, keyed by cellname
|
||||||
|
# Needs access to the PDK
|
||||||
|
def create_defs(args):
|
||||||
|
# replace this with a find
|
||||||
|
json_files = glob.glob('sky130_fd_sc_hd/latest/cells/*/definition.json')
|
||||||
|
definitions = {}
|
||||||
|
for json_file in json_files:
|
||||||
|
with open(json_file) as fh:
|
||||||
|
definition = json.load(fh)
|
||||||
|
definitions[definition['name']] = definition
|
||||||
|
|
||||||
|
with open('defs.json', 'w') as fh:
|
||||||
|
json.dump(definitions, fh)
|
||||||
Executable
+71
@@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import argparse
|
||||||
|
import documentation
|
||||||
|
import project
|
||||||
|
import reports
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description="TT setup")
|
||||||
|
parser.add_argument('--yaml', help="the project's yaml configuration file", default='info.yaml')
|
||||||
|
parser.add_argument('--run-dir', help="OpenLane run directory", default='runs/wokwi') # set in the github action yaml
|
||||||
|
parser.add_argument('--debug', help="debug logging", action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.INFO)
|
||||||
|
|
||||||
|
# tests & checks
|
||||||
|
parser.add_argument('--check-docs', help="check the documentation part of the yaml", action="store_const", const=True)
|
||||||
|
|
||||||
|
# reports & summaries
|
||||||
|
parser.add_argument('--create-cell-defs', help="create def file", action="store_const", const=True, default=False)
|
||||||
|
parser.add_argument('--print-cell-summary', help="print summary", action="store_const", const=True, default=False)
|
||||||
|
parser.add_argument('--print-cell-category', help="print category", action="store_const", const=True, default=False)
|
||||||
|
parser.add_argument('--print-stats', help="print some stats from the run", action="store_const", const=True)
|
||||||
|
parser.add_argument('--print-warnings', help="print any warnings", action="store_const", const=True)
|
||||||
|
|
||||||
|
# documentation
|
||||||
|
parser.add_argument('--create-project-pdf', help="create a single page PDF", action="store_const", const=True)
|
||||||
|
|
||||||
|
# configure
|
||||||
|
parser.add_argument('--create-user-config', help="create the user_config.tcl file with top module and source files", action="store_const", const=True)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# setup log
|
||||||
|
log_format = logging.Formatter('%(asctime)s - %(module)-10s - %(levelname)-8s - %(message)s')
|
||||||
|
# configure the client logging
|
||||||
|
log = logging.getLogger('')
|
||||||
|
# has to be set to debug as is the root logger
|
||||||
|
log.setLevel(args.loglevel)
|
||||||
|
|
||||||
|
# create console handler and set level to info
|
||||||
|
ch = logging.StreamHandler(sys.stdout)
|
||||||
|
# create formatter for console
|
||||||
|
ch.setFormatter(log_format)
|
||||||
|
log.addHandler(ch)
|
||||||
|
|
||||||
|
project_yaml = project.load_yaml(args)
|
||||||
|
|
||||||
|
# handle the options
|
||||||
|
if args.check_docs:
|
||||||
|
documentation.check_yaml_docs(project_yaml)
|
||||||
|
|
||||||
|
elif args.print_cell_summary or args.print_cell_category:
|
||||||
|
reports.summarize(args)
|
||||||
|
|
||||||
|
elif args.create_cell_defs:
|
||||||
|
reports.create_defs(args)
|
||||||
|
|
||||||
|
elif args.print_stats:
|
||||||
|
reports.print_stats(args)
|
||||||
|
|
||||||
|
elif args.print_warnings:
|
||||||
|
reports.print_warnings(args)
|
||||||
|
|
||||||
|
elif args.create_user_config:
|
||||||
|
project.create_user_config(project_yaml)
|
||||||
|
|
||||||
|
elif args.create_project_pdf:
|
||||||
|
documentation.create_pdf(project_yaml)
|
||||||
|
|
||||||
|
else:
|
||||||
|
parser.print_help()
|
||||||
Reference in New Issue
Block a user