add tt02 configure/info
diff --git a/configure.py b/configure.py
new file mode 100755
index 0000000..123d3cb
--- /dev/null
+++ b/configure.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python3
+import requests
+import argparse
+import os
+import glob
+import yaml
+import logging
+import sys
+import csv
+import re
+
+
+def load_yaml(yaml_file):
+ with open(yaml_file, "r") as stream:
+ return (yaml.safe_load(stream))
+
+
+def write_user_config(module_name, sources):
+ filename = 'user_config.tcl'
+ with open(os.path.join('src', filename), 'w') as fh:
+ fh.write("set ::env(DESIGN_NAME) {}\n".format(module_name))
+ 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 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)
+ 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)
+
+ filename = "user_module_{}.v".format(wokwi_id)
+ with open(os.path.join('src', filename), 'wb') as fh:
+ fh.write(r.content)
+
+ # also fetch the wokwi diagram
+ url = "https://wokwi.com/api/projects/{}/diagram.json".format(wokwi_id)
+ 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(os.path.join('src', "wokwi_diagram.json"), 'wb') as fh:
+ fh.write(r.content)
+
+ return [filename, '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)
+
+ return source_files
+
+
+# documentation
+def check_docs(yaml):
+ 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(f'Invalid format for discord username')
+ exit(1)
+
+
+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']
+
+
+def get_stats():
+ with open('runs/wokwi/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']))
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description="TT setup")
+
+ parser.add_argument('--check-docs', help="check the documentation part of the yaml", action="store_const", const=True)
+ parser.add_argument('--get-stats', help="print some stats from the run", action="store_const", const=True)
+ parser.add_argument('--create-user-config', help="create the user_config.tcl file with top module and source files", action="store_const", const=True)
+ parser.add_argument('--debug', help="debug logging", action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.INFO)
+ parser.add_argument('--yaml', help="yaml file to load", default='info.yaml')
+
+ 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)
+
+ if args.get_stats:
+ get_stats()
+
+ elif args.check_docs:
+ logging.info("checking docs")
+ config = load_yaml(args.yaml)
+ check_docs(config)
+
+ elif args.create_user_config:
+ logging.info("creating include file")
+ config = load_yaml(args.yaml)
+ source_files = get_project_source(config)
+ top_module = get_top_module(config)
+ assert top_module != 'top'
+ write_user_config(top_module, source_files)
diff --git a/info.yaml b/info.yaml
new file mode 100644
index 0000000..482c112
--- /dev/null
+++ b/info.yaml
@@ -0,0 +1,46 @@
+---
+# TinyTapeout project information
+project:
+ wokwi_id: 0 # If using wokwi, set this to your project's ID
+# source_files: # If using an HDL, set wokwi_id as 0 and uncomment and list your source files here. Source files must be in ./src
+# - counter.v
+# - decoder.v
+# top_module: "seven_segment_seconds" # put the name of your top module here, make it unique by prepending your github username
+
+# As everyone will have access to all designs, try to make it easy for someone new to your design to know what
+# it does and how to operate it.
+#
+# Here is an example: https://github.com/mattvenn/tinytapeout_m_segments/blob/main/info.yaml
+#
+# This info will be automatically collected and used to make a datasheet for the chip.
+documentation:
+ author: "" # Your name
+ discord: "" # Your discord handle - make sure to include the # part as well
+ title: "" # Project title
+ description: "" # Short description of what your project does
+ how_it_works: "" # Longer description of how the project works
+ how_to_test: "" # Instructions on how someone could test your project, include things like what buttons do what and how to set the clock if needed
+ external_hw: "" # Describe any external hardware needed
+ language: "wokwi" # other examples include Verilog, Amaranth, VHDL, etc
+ doc_link: "" # URL to longer form documentation, eg the README.md in your repository
+ clock_hz: 0 # Clock frequency in Hz (if required) we are expecting max clock frequency to be ~6khz. Provided on input 0.
+ picture: "" # relative path to a picture in your repository
+ inputs: # a description of what the inputs do
+ - clock
+ - reset
+ - none
+ - none
+ - none
+ - none
+ - none
+ - none
+ outputs:
+ - segment a # a description of what the outputs do
+ - segment b
+ - segment c
+ - segment d
+ - segment e
+ - segment f
+ - segment g
+ - none
+