[doc] Completely replace docgen with hugo

This change completely replaces docgen and replaces or removes
docgen-specific markdown in documentation.  It also does the following:

  * Updates all local links to use hugo relative references so that a
    broken link is a broken build.
  * Uses upstream wavedrom, which breaks at least one page that depends
    on local modifications.
  * Renames most hw/ip/**/ip_name.doc and dv_plan documents for a more
    aesthetic document tree layout.
  * Moves some doc/ pages into their own page bundle.
  * Updates util/build_docs.py to pre-generate registers, hwcfg, and
    dashboard fragments and invoke hugo.
diff --git a/util/_index.md b/util/_index.md
new file mode 100644
index 0000000..4b5e386
--- /dev/null
+++ b/util/_index.md
@@ -0,0 +1,12 @@
+# Tools
+
+These are predominantly Readme's with details about the tooling scripts. Make sure to also check the corresponding [Reference Manuals]({{< relref "doc/rm" >}}).
+
+* [container]({{< relref "./container/README.md" >}})
+* [fpga]({{< relref "./fpga/README.md" >}})
+* [reggen]({{< relref "./reggen/README.md" >}})
+* [simplespi]({{< relref "./simplespi/README.md" >}})
+* [testplanner]({{< relref "./testplanner/README.md" >}})
+* [tlgen]({{< relref "./tlgen/README.md" >}})
+* [uvmdvgen]({{< relref "./uvmdvgen/README.md" >}})
+* [wavegen]({{< relref "./wavegen/README.md" >}})
diff --git a/util/build_docs.py b/util/build_docs.py
index 00389b0..cea7709 100755
--- a/util/build_docs.py
+++ b/util/build_docs.py
@@ -3,130 +3,154 @@
 # Licensed under the Apache License, Version 2.0, see LICENSE for details.
 # SPDX-License-Identifier: Apache-2.0
 #
-# pip3 install --user livereload
 # Usage:
 #   run './build_docs.py' to generate the documentation and keep it updated
-#   open 'http://localhost:5500/' to check live update (this opens the top
+#   open 'http://localhost:1313/' to check live update (this opens the top
 #   level index page). you can also directly access a specific document by
-#   accessing 'http://localhost:5500/path/to/doc.html',
-#       e.g. http://localhost:5500/hw/ip/uart/doc/uart.html
+#   accessing 'http://localhost:1313/path/to/doc',
+#       e.g. http://localhost:1313/hw/ip/uart/doc
 
 import argparse
+import io
 import logging
 import os
 import shutil
+import subprocess
 from pathlib import Path
 
-import livereload
+import hjson
 
-import docgen.generate
+import dashboard.gen_dashboard_entry as gen_dashboard_entry
+import reggen.gen_cfg_html as gen_cfg_html
+import reggen.gen_html as gen_html
+import reggen.validate as validate
+import testplanner.testplan_utils as testplan_utils
 
 USAGE = """
   build_docs [options]
 """
 
-MARKDOWN_EXTENSIONS = [
-    '.md',
-    '.mkd',
-]
-STATIC_ASSET_EXTENSIONS = [
-    '.svg',
-    '.png',
-    '.jpg',
-    '.css',
-]
-HJSON_EXTENSIONS = ['.hjson']
-
 # Configurations
 # TODO: Move to config.yaml
 SRCTREE_TOP = Path(__file__).parent.joinpath('..').resolve()
 config = {
     # Toplevel source directory
-    "topdir": SRCTREE_TOP,
+    "topdir":
+    SRCTREE_TOP,
 
-    # A list of directories containing documentation within topdir. To ensure
-    # the top-level sitemap doesn't have broken links, this should be kept
-    # in-sync with the doctree tag in sitemap.md.
-    "incdirs": ['./doc', './hw', './sw', './util'],
+    # Pre-generate register and hwcfg fragments from these files.
+    "hardware_definitions": [
+        "hw/ip/aes/data/aes.hjson",
+        "hw/ip/alert_handler/data/alert_handler.hjson",
+        "hw/ip/flash_ctrl/data/flash_ctrl.hjson",
+        "hw/ip/gpio/data/gpio.hjson",
+        "hw/ip/hmac/data/hmac.hjson",
+        "hw/ip/i2c/data/i2c.hjson",
+        "hw/ip/padctrl/data/padctrl.hjson",
+        "hw/ip/pinmux/data/pinmux.hjson",
+        "hw/ip/rv_plic/data/rv_plic.hjson",
+        "hw/ip/rv_timer/data/rv_timer.hjson",
+        "hw/ip/spi_device/data/spi_device.hjson",
+        "hw/ip/uart/data/uart.hjson",
+        "hw/ip/usbdev/data/usbdev.hjson",
+        "hw/ip/usbuart/data/usbuart.hjson",
+    ],
+
+    # Pre-generate dashboard fragments from these directories.
+    "dashboard_definitions": [
+        "hw/ip",
+    ],
+
+    # Pre-generate testplan fragments from these files.
+    "testplan_definitions": [
+        "hw/ip/gpio/data/gpio_testplan.hjson",
+        "hw/ip/hmac/data/hmac_testplan.hjson",
+        "hw/ip/i2c/data/i2c_testplan.hjson",
+        "hw/ip/rv_timer/data/rv_timer_testplan.hjson",
+        "hw/ip/uart/data/uart_testplan.hjson",
+        "util/testplanner/examples/foo_testplan.hjson",
+    ],
 
     # Output directory for documents
-    "outdir": SRCTREE_TOP.joinpath('opentitan-docs'),
-    "verbose": False,
+    "outdir":
+    SRCTREE_TOP.joinpath('build', 'docs'),
+    "outdir-generated":
+    SRCTREE_TOP.joinpath('build', 'docs-generated'),
+    "verbose":
+    False,
 }
 
 
-def get_doc_files(extensions=MARKDOWN_EXTENSIONS + STATIC_ASSET_EXTENSIONS):
-    """Get the absolute path of files containing documentation
-    """
-    file_list = []
-    # doc files on toplevel
-    for ext in extensions:
-        file_list += config["topdir"].glob('*' + ext)
-    # doc files in include dirs
-    for incdir in config['incdirs']:
-        for ext in extensions:
-            file_list += config["topdir"].joinpath(incdir).rglob('*' + ext)
-    return file_list
+def generate_dashboards():
+    for dashboard in config["dashboard_definitions"]:
+        hjson_paths = []
+        hjson_paths.extend(
+            sorted(SRCTREE_TOP.joinpath(dashboard).rglob('*.prj.hjson')))
+
+        dashboard_path = config["outdir-generated"].joinpath(
+            dashboard, 'dashboard')
+        dashboard_html = open(dashboard_path, mode='w')
+        for hjson_path in hjson_paths:
+            gen_dashboard_entry.gen_dashboard_html(hjson_path, dashboard_html)
+        dashboard_html.close()
 
 
-def ensure_dest_dir(dest_pathname):
-    os.makedirs(dest_pathname.parent, exist_ok=True)
+def generate_hardware_blocks():
+    for hardware in config["hardware_definitions"]:
+        hardware_file = open(SRCTREE_TOP.joinpath(hardware))
+        regs = hjson.load(hardware_file,
+                          use_decimal=True,
+                          object_pairs_hook=validate.checking_dict)
+        if validate.validate(regs) == 0:
+            logging.info("Parsed %s" % (hardware))
+        else:
+            logging.fatal("Failed to parse %s" % (hardware))
+
+        base_path = config["outdir-generated"].joinpath(hardware)
+        base_path.parent.mkdir(parents=True, exist_ok=True)
+
+        regs_html = open(base_path.parent.joinpath(base_path.name +
+                                                   '.registers'),
+                         mode='w')
+        gen_html.gen_html(regs, regs_html)
+        regs_html.close()
+
+        hwcfg_html = open(base_path.parent.joinpath(base_path.name + '.hwcfg'),
+                          mode='w')
+        gen_cfg_html.gen_cfg_html(regs, hwcfg_html)
+        hwcfg_html.close()
 
 
-def path_src_to_dest(src_pathname, dest_filename_suffix=None):
-    """Get the destination pathname from a source pathname
-    """
-    src_relpath = Path(src_pathname).relative_to(config["topdir"])
-    dest_pathname = Path(config["outdir"]).joinpath(src_relpath)
-    if dest_filename_suffix:
-        dest_pathname = dest_pathname.with_suffix(dest_filename_suffix)
-    return dest_pathname
+def generate_testplans():
+    for testplan in config["testplan_definitions"]:
+        plan = testplan_utils.parse_testplan(SRCTREE_TOP.joinpath(testplan))
+
+        plan_path = config["outdir-generated"].joinpath(testplan + '.testplan')
+        plan_path.parent.mkdir(parents=True, exist_ok=True)
+
+        testplan_html = open(plan_path, mode='w')
+        testplan_utils.gen_html_testplan_table(plan, testplan_html)
+        testplan_html.close()
 
 
-def process_file_markdown(src_pathname):
-    """Process a markdown file and copy it to the destination
-    """
-    dest_pathname = path_src_to_dest(src_pathname, '.html')
-
-    logging.info("Processing Markdown file: %s -> %s" %
-                 (str(src_pathname), str(dest_pathname)))
-
-    ensure_dest_dir(dest_pathname)
-
-    with open(dest_pathname, 'w', encoding='UTF-8') as f:
-        outstr = docgen.generate.generate_doc(str(src_pathname),
-                                              verbose=config['verbose'],
-                                              inlinecss=True,
-                                              inlinewave=True,
-                                              asdiv=False)
-        f.write(outstr)
-
-    return dest_pathname
-
-
-def process_file_copytodest(src_pathname):
-    """Copy a file to the destination directory with no further processing
-    """
-    dest_pathname = path_src_to_dest(src_pathname)
-
-    logging.info("Copying %s -> %s" % (str(src_pathname), str(dest_pathname)))
-
-    ensure_dest_dir(dest_pathname)
-    shutil.copy(src_pathname, dest_pathname)
-
-
-def process_all_files():
-    """Process all files
-
-    The specific processing action depends on the file type.
-    """
-    src_files = get_doc_files()
-
-    for src_pathname in src_files:
-        if src_pathname.suffix in MARKDOWN_EXTENSIONS:
-            process_file_markdown(src_pathname)
-        elif src_pathname.suffix in STATIC_ASSET_EXTENSIONS:
-            process_file_copytodest(src_pathname)
+def invoke_hugo(preview):
+    site_docs = SRCTREE_TOP.joinpath('site', 'docs')
+    config_file = str(site_docs.joinpath('config.toml'))
+    layout_dir = str(site_docs.joinpath('layouts'))
+    args = [
+        "hugo",
+        "--config",
+        config_file,
+        "--destination",
+        str(config["outdir"]),
+        "--contentDir",
+        str(SRCTREE_TOP),
+        "--layoutDir",
+        layout_dir,
+    ]
+    if preview:
+        args += ["server"]
+    subprocess.run(args, check=True, cwd=SRCTREE_TOP)
 
 
 def main():
@@ -144,21 +168,14 @@
         help="""starts a local server with live reload (updates triggered upon
              changes in the documentation files). this feature is intended
              to preview the documentation locally.""")
+    parser.add_argument('--hugo', help="""TODO""")
 
     args = parser.parse_args()
 
-    # Initial processing of all files
-    process_all_files()
-
-    if args.preview:
-        # Setup livereload watcher
-        server = livereload.Server()
-        exts_to_watch = MARKDOWN_EXTENSIONS +       \
-                        STATIC_ASSET_EXTENSIONS +   \
-                        HJSON_EXTENSIONS
-        for src_pathname in get_doc_files(exts_to_watch):
-            server.watch(str(src_pathname), process_all_files)
-        server.serve(root=config['topdir'].joinpath(config['outdir']))
+    generate_hardware_blocks()
+    generate_dashboards()
+    generate_testplans()
+    invoke_hugo(args.preview)
 
 
 if __name__ == "__main__":
diff --git a/util/docgen.py b/util/docgen.py
deleted file mode 100755
index 7e62889..0000000
--- a/util/docgen.py
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/env python3
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-r"""Command-line tool to merge markdown and register spec to html
-
-"""
-import argparse
-import logging as log
-import os.path
-import shutil
-import sys
-
-from pkg_resources import resource_filename
-
-from docgen import generate, html_data, lowrisc_renderer
-from reggen import version
-
-USAGE = """
-  docgen [options]
-  docgen [options] <file>
-  docgen (-h | --help)
-  docgen --version
-"""
-
-
-def main():
-    parser = argparse.ArgumentParser(
-        prog="docgen",
-        formatter_class=argparse.RawDescriptionHelpFormatter,
-        usage=USAGE,
-        description=__doc__,
-        epilog='defaults or the filename - can be used for stdin/stdout')
-    parser.add_argument(
-        '--version', action='store_true', help='Show version and exit')
-    parser.add_argument(
-        '-v',
-        '--verbose',
-        action='store_true',
-        help='Verbose output during processing')
-    parser.add_argument(
-        '-c',
-        '--inline-css',
-        action='store_true',
-        help='Put CSS inline in output file')
-    parser.add_argument(
-        '-d',
-        '--asdiv',
-        action='store_true',
-        help='Output as a <div> without html header/trailer')
-    parser.add_argument(
-        '-j',
-        '--wavesvg-usejs',
-        action='store_true',
-        help='Waveforms should use javascript wavedrom '
-        'rather than generating inline svg')
-    parser.add_argument(
-        '-o',
-        '--output',
-        type=argparse.FileType('w'),
-        default=sys.stdout,
-        metavar='file',
-        help='Output file (default stdout)')
-    parser.add_argument(
-        'srcfile',
-        nargs='?',
-        metavar='file',
-        default='-',
-        help='source markdown file (default stdin)')
-    args = parser.parse_args()
-
-    if args.version:
-        version.show_and_exit(__file__, ["Hjson", "Mistletoe"])
-
-    if (args.verbose):
-        log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
-    else:
-        log.basicConfig(format="%(levelname)s: %(message)s")
-
-    outfile = args.output
-
-    with outfile:
-        outfile.write(
-            generate.generate_doc(args.srcfile, args.verbose, args.inline_css,
-                                  not args.wavesvg_usejs, args.asdiv))
-
-
-if __name__ == '__main__':
-    main()
diff --git a/util/docgen/LICENSE.mistletoe b/util/docgen/LICENSE.mistletoe
deleted file mode 100644
index 9ad0f5a..0000000
--- a/util/docgen/LICENSE.mistletoe
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License
-
-Copyright 2017 Mi Yu
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/util/docgen/README.md b/util/docgen/README.md
deleted file mode 100644
index faf93c4..0000000
--- a/util/docgen/README.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Docgen -- lowRISC Document generator
-
-Docgen is a python3 tool to read markdown documentation and generate html.
-
-It works in conjunction with reggen to generate documentation with the
-register information inserted. Examples are described in the README.md
-in the examples subdirectory.
-
-The lowRISC markdown is based on CommonMark (A strongly defined, highly
-compatible specification of Markdown defined at
-https://commonmark.org/ ) parsed by mistletoe (a fast, extensible and
-spec-compliant Markdown parser in pure Python).
-
-Mistletoe already adds tables using the Github markdown syntax.
-
-The following extensions have been made for the lowRISC version:
-* `{{% lowrisc-doc-hdr Title Of Doc }}` Insert a standard title header
-  and give
-  the document a title. Expected to extend this to have lowrisc-doc-hdr=type
-  (type could be component, core, guide,...) to allow the tool to
-  validate required sections are in the document.
-
-* `{{% regfile filename.hjson }}` Pointer to the register definition
-  json/hjson. This is expected to go early in the document. After this line
-  the registers are available as markup items.
-
-* `{{% registers x }}` Insert the register tables at this point in the
-  document. Must be after the regfile extension! TODO fix the need for `x`
-
-* `{{% import_testplan testplan.hjson }}` Pointer to the testplan
-  hjson. This is expected to go early in the document. After this line
-  the testplan entries are available as markup items.
-
-* `{{% insert_testplan x }}` Insert the testplan table at this point in the
-  document. Must be after the `import_testplan` extension! TODO fix the need for `x`
-
-* `{{% include file }}` Insert the file into the markdown
-  document. Any other text on the same line as the include directive
-  will be inserted, then a newline and then the included file. The
-  file is included before any other processing so the result is a
-  single file processed by the markdown processor (thus all
-  definitions like anchor links are global and not confined to the
-  file they are in). Includes may be nested. The filename is relative
-  to the directory that the markdown file currently being processed is
-  in (so relative links work from inside included files). If the
-  include file is not found then an error is reported and a line
-  indicating the error will be inserted in the markdown.
-
-* `{{% include !command -options }}` Use the shell to cd to the
-  directory that the markdown file is in and run the command with
-  given options (everything from the `!` to the closing `}}` is used
-  as the shell command). Insert the output (stdout) from the command
-  into the markdown document. Any other text on the same line as the
-  include directive will be inserted, then a newline and then the
-  command output. (As a result, if the triple back-tick to start a
-  code block immediately follows the `}}` then the output from the
-  command will be inserted inside that code block.) Error returns from
-  the command will be ignored, and any output on stderr will be
-  reported in the docgen stderr output.
-
-
-* `!!Reg` or `!!Reg.Field` Insert Component.Reg or Component.Reg.Field
-  in the output file as a link to the register table for Reg and
-  tagged for special CSS decoration (currently makes them blue,
-  monospace and a little smaller). If Reg is not in the list of
-  registers read from the regfile directive then a warning is printed
-  and the output is not transformed. (Note the use of period rather
-  than underline as the separator was to avoid syntax highlighter
-  issuses because of markdown's use of underline for italics.
-
-* ` ```lang ` Code blocks are highlighted by pygments (a generic
-  syntax highlighter in python). Background colour can be set using the
-  {.good} and {.bad} tags after the lang.
-
-* ` ```wavejson ` Code blocks describing waveforms are converted into
-  an svg picture in the output file. The `-j` or `--wavesvg-usejs` flag
-  will instead generate the <script> output needed by the WaveDrom
-  javascript parser and include invocation of wavedrom in the output
-  html.
-
-
-* Anticipate adding support for ToC generation and insertion (there is
-  partial support for this already in mistletoe)
diff --git a/util/docgen/__init__.py b/util/docgen/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/util/docgen/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/util/docgen/examples/README.md b/util/docgen/examples/README.md
deleted file mode 100644
index 5646693..0000000
--- a/util/docgen/examples/README.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# Examples using docgen
-
-This directory has some examples of using docgen. The example commands
-assume $REPO_TOP is set to the toplevel directory of the repo.
-
-### Setup
-
-If packages have not previously been installed you will need to set a
-few things up. First use `pip3` to install some required packages:
-```
-$ pip3 install --user hjson
-$ pip3 install --user mistletoe
-$ pip3 install --user pygments
-```
-
-The examples all use the -c flag to ensure CSS styles are included
-inline in the html file generated. If building a site this flag will
-likely not be used. If this flag is not given then `md_html.css` from
-docgen and `reg_html.css` from reggen should be put in the same
-directory as the html file.
-
-### Build example1
-
-Example 1 is the Simple Uart. There are a couple of changes from the
-actuall implemmentation: the registers are declared as 64-bit and the
-STATECLR register bits have been moved up by 16 bits.
-
-```
-$ cd $REPO_TOP/util/docgen/examples
-$ ../../docgen.py -c uart.md > /tmp/uartout.html
-```
-
-If you want it to tell more about progress add the verbose flag. Note
-that this causes a second validation pass that checks the output of
-the first pass, there should be fewer things to do on the second pass.
-
-```
-$ cd $REPO_TOP/util/docgen/examples
-$ ../../docgen.py -c -v uart.md > /tmp/uartout.html
-```
-
-You can open the output using file:///tmp/uartout.html
-
-### Build example2
-
-Example 2 is a 16550 style Uart. This shows 8-bit registers and
-registers at the same address.
-
-Note this example has a deliberate error in the second waveform description.
-
-```
-$ cd $REPO_TOP/util/docgen/examples
-$ ../../docgen.py -c uart16550.md > /tmp/uart16550out.html
-```
-
-If you want it to tell more about progress add the verbose flag. Note
-that this causes a second validation pass that checks the output of
-the first pass, there should be fewer things to do on the second pass.
-
-```
-$ cd $REPO_TOP/util/docgen/examples
-$ ../../docgen.py -c -v uart16550.md > /tmp/uart16550out.html
-```
-
-The waveforms can also be generated using the browser-based wavedom
-javascript.
-
-```
-$ cd $REPO_TOP/util/docgen/examples
-$ ../../docgen.py -cj uart16550.md > /tmp/uart16550out.html
-```
-
-
-You can open the output using file:///tmp/uart16550out.html
-
-### Build example 3
-
-Example 3 is an example of using the multireg key to generate registers.
-
-
-```
-$ cd $REPO_TOP/util/docgen/examples
-$ ../../docgen.py -c gp.md > /tmp/gpout.html
-```
diff --git a/util/docgen/examples/badwen.hjson b/util/docgen/examples/badwen.hjson
deleted file mode 100644
index 07eedad..0000000
--- a/util/docgen/examples/badwen.hjson
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-{
-  name: "BADWEN",
-  clock_primary: "clk_fixed",
-  bus_device: "tlul",
-
-  regwidth: "32",
-  registers: [
-    {name: "RDATA", desc: "UART read data",
-      swaccess: "ro", fields: [
-      {bits: "7:0", resval: "0x0"}
-    ]},
-    {name: "WDATA", desc: "UART write data", swaccess: "wo", fields: [
-      {bits: "7:0", resval: "0x0"}
-    ]},
-    {name: "NCO", desc: "Baud clock rate control",
-      swaccess: "rw", regwen: "GOODWEN", fields: [
-      {bits: "15:0", resval: "0b0"}
-    ]},
-    {name: "NCO1", desc: "Baud clock rate control",
-      swaccess: "rw", regwen: "BADWEN1", fields: [
-      {bits: "15:0", resval: "0b0"}
-    ]},
-    {name: "NCO2", desc: "Baud clock rate control",
-      swaccess: "rw", regwen: "BADWEN2", fields: [
-      {bits: "15:0", resval: "0b0"}
-    ]},
-    {name: "NCO3", desc: "Baud clock rate control",
-      swaccess: "rw", regwen: "BADWEN3", fields: [
-      {bits: "15:0", resval: "0b0"}
-    ]},
-    {name: "NCO4", desc: "Baud clock rate control",
-      swaccess: "rw", regwen: "NONE", fields: [
-      {bits: "15:0", resval: "0b0"}
-    ]},
-    {name: "GOODWEN", desc: "Write enable control",
-      swaccess: "rw1c", fields: [
-      {name: "wen", desc: "wr enable", bits: "0", resval: "1"}
-    ]},
-    {name: "BADWEN1", desc: "Write enable control too many bits",
-      swaccess: "rw1c", fields: [
-      {name: "wen", desc: "wr enable", bits: "0", resval: "1"}
-      {name: "foo", desc: "wr enable", bits: "1", resval: "1"}
-    ]},
-    {name: "BADWEN2", desc: "Write enable control not rw1c",
-      swaccess: "rw", fields: [
-      {name: "wen", desc: "wr enable", bits: "0", resval: "1"}
-    ]},
-    {name: "BADWEN3", desc: "Write enable control not default to 1",
-      swaccess: "rw1c", fields: [
-      {name: "wen", desc: "wr enable", bits: "0", resval: "0"}
-    ]},
-    {name: "DVREG", desc: "DV-accessible test register", swaccess: "rw",
-     fields: [
-      {bits: "7:0", name: "", desc: "-" }
-    ]}
-  ]
-}
diff --git a/util/docgen/examples/badwen.md b/util/docgen/examples/badwen.md
deleted file mode 100644
index c8cc971..0000000
--- a/util/docgen/examples/badwen.md
+++ /dev/null
@@ -1,31 +0,0 @@
-{{% lowrisc-doc-hdr Test for register write enable errors }}
-{{% regfile badwen.hjson }}
-
-Blah
-
-{{% toc 3 }}
-
-## Compatibility
-
-## Theory of operation
-
-Check for cross reference to !!RDATA
-
-## Programmer Guide
-
-
-### Initialization
-
-
-### Interrupts
-
-
-
-### Debug Features
-
-
-## Implementation Guide
-
-
-## Registers
-{{% registers x }}
diff --git a/util/docgen/examples/errors.hjson b/util/docgen/examples/errors.hjson
deleted file mode 100644
index 0e8e5a1..0000000
--- a/util/docgen/examples/errors.hjson
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-{
-  name: "ERR",
-  clock_primary: "clk_fixed",
-  bus_device: "tlul",
-
-  regwidth: "32",
-  registers: [
-    { name: "OE",
-      desc: '''GPIO Output Enable
-
-            bit[i]=1'b0: Input mode for GPIO[i]
-            bit[i]=1'b1: Output mode for GPIO[i]
-            ''',
-      swaccess: "rw",
-      fields: [
-        { bits: "31:0" }
-      ],
-    },
-    { reserved: "4" }
-    { reserved: "4" name: "error" }
-    { name: "DATA_IN",
-      desc: "GPIO Input data read bitfield",
-      swaccess: "ro",
-      fields: [
-        { bits: "31:0",
-          resval: "x"
-        }
-      ],
-    },
-    { name: "DATA_IN",
-      desc: "Duplicate name",
-      swaccess: "ro",
-      fields: [
-        { bits: "0", name: "abit", desc: "a bit"},
-        { bits: "1", name: "abit", desc: "a bit duplicate name"},
-	{ bits: "32", name: "bbit", desc: "out of bounds bit"},
-      ],
-    },
-    { name: "DATA_BB",
-      desc: "should be ok",
-      swaccess: "ro",
-      fields: [
-        { bits: "0", name: "abit", desc: "a bit"},
-	{ bits: "1", name: "bbit", desc: "ok"},
-      ],
-    },
-    { name: "data_bb",
-      desc: "Duplicate name although the case differs",
-      swaccess: "ro",
-      fields: [
-        { bits: "0", name: "abit", desc: "a bit"},
-	{ bits: "1", name: "bbit", desc: "ok"},
-      ],
-    },
-    { name: "DATA_YY",
-      desc: "Name ok should show field errors",
-      swaccess: "ro",
-      fields: [
-        { bits: "0", name: "abit", desc: "a bit"},
-        { bits: "1", name: "abit", desc: "a bit duplicate name"},
-	{ bits: "32", name: "bbit", desc: "out of bounds bit"},
-      ],
-    },
-    { name: "DATA_ZZ",
-      desc: "More errors two swaccess",
-      swaccess: "ro",
-      swaccess: "rw",
-      fields: [
-        { bits: "0", name: "abit", desc: "a bit"},
-        { bits: 1, name: "intbit", desc: "bit is an integer"},
-	{ bits: "32:20", name: "bbit", desc: "out of bounds bit range"},
-      ],
-    },
-    { name: "DATA_QQ",
-      desc: "No fields",
-      swaccess: "rw",
-      fields: [
-      ],
-    },
-    # multireg for single bit instance?
-    { multireg: {
-        name: "DATA_OUT",
-        desc: "GPIO output data",
-        count: "32",
-        cname: "GPIO",
-        swaccess: "rw",
-        fields: [
-          { bits: "0", name: "D" desc: "Output data" }
-        ],
-      }
-    },
-    {sameaddr: [
-	{name: "IIR", desc: "Interrupt identification register",
-	 resval: "0xa0", swaccess: "ro", fields: [
-	     {bits: "0", name: "INT", resval: "1",
-	      desc: "This bit is clear if the UART is interrupting."
-	     }
-	     {bits: "3:1", name: "TYPE",
-	      desc: '''
-              If the INT bit is clear, these bits indicate the highest
-              priority pending interrupt.
-              '''
-	      enum: [
-      		 { value: "0", name: "mdm", desc: "Modem status (lowest)" },
-       		 { value: "1", name: "txe", desc: "TX holding register empty" },
-       		 { value: "2", name: "rxd", desc: "RX data available" },
-       		 { value: "3", name: "rxl", desc: "RX line status (highest)" }
-	      ]
-	     }
-	     {bits: "3", name: "TO",
-	      desc: "This bit overlaps."
-	      resval: "NaN"
-	     }
-	     {bits: "5", name: "F64", resval: "1",
-	      desc: "Will always be clear because the FIFO is not 64 bytes."
-	     }
-	     {bits: "7:6", resval: "6", name: "FEN", desc: '''
-	      These bits will both be clear if the FIFO is disabled
-	      and both be set if it is enabled.
-              '''
-	      enum: [
-      		 { value: "0", name: "mdm", desc: "Modem status (lowest)" },
-       		 { value: "1", name: "txe", desc: "TX holding register empty" },
-       		 { value: "2", name: "rxd", desc: "RX data available" },
-       		 { value: "3", name: "rxl" }
-	      ]
-	     }
-	 ]}
-	{name: "FCR", desc: "FIFO Control Register",
-	 swaccess: "ab", fields: [
-	     {bits: "0", name: "FEN",
-	      desc: "This bit must be set to enable the FIFOs."
-	     }
-	     {bits: "1", name: "CRX", desc: '''
-               Writing this bit with a 1 will reset the RX fifo. The
-               bit will clear after the FIFO is reset.
-              '''
-	     }
-	     {bits: "2", name: "CTX", desc: '''
-               Writing this bit with a 1 will reset the TX fifo. The
-               bit will clear after the FIFO is reset.
-              '''
-	     }
-	     {bits: "3", name: "DMAS",
-	      desc: "DMA Mode Select. This bit is not used."
-	     }
-	     {bits: "5", name: "E64",
-	      desc: "This bit is reserved because the FIFO is not 64 bytes."
-	     }
-	     {bits: "6:7", name: "NOTPPC",
-	      desc: '''
-                These two bits set the interrupt trigger level for the
-                receive FIFO. The received data available interrupt
-                will be set when there are at least this number of
-                bytes in the receive FIFO.
-              '''
-	      enum: [
-      		 { value: "0", name: "rxlvl1", desc: "1 Byte" },
-       		 { value: "1", name: "rxlvl4", desc: "4 Bytes" },
-       		 { value: "2", name: "rxlvl8", desc: "8 bytes" },
-       		 { value: "3", name: "rxlvl14", desc: "14 bytes" }
-	      ]
-	     }
-	 ]}
-    ]}
-    // skipto bad offset
-    { skipto: "0x41" }
-    // Backwards skip is an error
-    { skipto: "16" }
-    {window: {
-    	     name: "FCR"
-	     items: "16"
-	     validbits: "48"
-	     byte-write: "True"
-	     swaccess: "rw"
-	     desc: '''
-	     	   Duplicate name, too wide.
-		   '''
-	}
-    },
-    {window: {
-    	     name: "win1"
-	     items: "16"
-	     validbits: "48"
-	     byte-write: "True"
-	     swaccess: "rw"
-	     desc: '''
-	     	   Too wide.
-		   '''
-	}
-    },
-    {window: {
-    	     name: "win2"
-	     items: "big"
-	     validbits: "x"
-	     byte-write: "True"
-	     swaccess: "read"
-	     desc: '''
-	     	   size, width not a number, bad swaccess
-		   '''
-	}
-    },
-
-  ]
-}
diff --git a/util/docgen/examples/errors.md b/util/docgen/examples/errors.md
deleted file mode 100644
index db9ee1d..0000000
--- a/util/docgen/examples/errors.md
+++ /dev/null
@@ -1,55 +0,0 @@
-{{% lowrisc-doc-hdr Example with lots of errors }}
-{{% regfile errors.hjson }}
-
-Blah
-
-Error in lowRISC tag
-{{% bob 3 }}
-
-## Compatibility
-
-
-## Theory of operation
-
-Check for cross reference to !!DATA_OUT and !!INT_CTRL and !!INT_CTRL2 blah
-
-For testing, this version should report an error:
-```wavejson
-{signal: [
-  {name:'Baud Clock',  wave: 'p...........' },
-  {name:'Data 8 bit',        wave: '10========1=',
-   data: [ "lsb", "", "", "", "", "", "", "msb", "next" ] )
-  {name:'Data 7 bit',        wave: '10=======1=.',
-   data: [ "lsb", "", "", "", "", "", "msb", "next" ] },
-  {name:'Data 6 bit',        wave: '10======1=..',
-   data: [ "lsb", "", "", "", "", "msb", "next" ] },
-  {name:'Data 5 bit',        wave: '10=====1=...',
-   data: [ "lsb", "", "", "", "msb", "next" ] },
-  {name:'8 with Parity', wave: '10=========1',
-   data: [ "lsb", "", "", "", "", "", "", "msb", "par" ] },
- ],
- head:{
-   text:'Serial Line format (one stop bit)',
-   tock:-1,
- }
-}
-```
-
-## Programmer Guide
-
-
-### Initialization
-
-
-### Interrupts
-
-
-
-### Debug Features
-
-
-## Implementation Guide
-
-
-## Registers
-{{% registers x }}
diff --git a/util/docgen/examples/gp.hjson b/util/docgen/examples/gp.hjson
deleted file mode 100644
index 1329d55..0000000
--- a/util/docgen/examples/gp.hjson
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-{
-  name: "GP",
-  clock_primary: "clk_fixed",
-  bus_device: "tlul",
-
-  regwidth: "32",
-  registers: [
-    { name: "OE",
-      desc: '''GPIO Output Enable
-
-            bit[i]=1'b0: Input mode for GPIO[i]
-            bit[i]=1'b1: Output mode for GPIO[i]
-            ''',
-      swaccess: "rw",
-      fields: [
-        { bits: "31:0" }
-      ],
-    },
-    { reserved: "4" }
-    { name: "DATA_IN",
-      desc: "GPIO Input data read bitfield",
-      swaccess: "ro",
-      fields: [
-        { bits: "31:0",
-          resval: "x"
-        }
-      ],
-    },
-    # multireg for single bit instance?
-    { multireg: {
-        name: "DATA_OUT",
-        desc: "GPIO output data",
-        count: "32",
-        cname: "GPIO",
-        swaccess: "rw",
-        fields: [
-          { bits: "0", name: "D" desc: "Output data" }
-        ],
-      }
-    },
-
-    { multireg: {
-          name: "INT_CTRL",
-	  desc: "GPIO Interrupt control",
-	  count: "32",
-	  cname: "GPIO",
-	  swaccess: "rw",
-	  fields: [
-	      { bits: "0", name: "POS", resval: "0",
-	        desc: "Set to interrupt on rising edge"
-	      }
-	      { bits: "1", name: "NEG", resval: "0",
-	        desc: "Set to interrupt on falling edge"
-	      }
-	      { bits: "4:2", name: "TYPE", resval: "0",
-	        desc: "Type of interrupt to raise"
-		enum: [
-		  {value: "0", name: "none", desc: "log but no interrupt" },
-		  {value: "1", name: "low", desc: "low priotiry interrupt" },
-		  {value: "2", name: "high", desc: "high priotiry interrupt" },
-		  {value: "3", name: "nmi", desc: "non maskable interrupt" }
-		]
-	      }
-	  ]
-      }
-    },
-    { multireg: {
-          name: "WDATA",
-	  desc: "Write with mask to GPIO out register",
-	  count: "32",
-	  cname: "GPIO",
-	  swaccess: "rw",
-	  fields: [
-	      { bits: "0", name: "DATA", resval: "0",
-	        desc: "Data to write if mask bit is 1"
-	      }
-	      { bits: "16", name: "MASK", resval: "0",
-	        desc: "Set to allow data write"
-	      }
-	  ]
-      }
-    }
-  ]
-}
diff --git a/util/docgen/examples/gp.md b/util/docgen/examples/gp.md
deleted file mode 100644
index 510a48c..0000000
--- a/util/docgen/examples/gp.md
+++ /dev/null
@@ -1,32 +0,0 @@
-{{% lowrisc-doc-hdr Example like first gpio }}
-{{% regfile gp.hjson }}
-
-Blah
-
-{{% toc 3 }}
-
-## Compatibility
-
-
-## Theory of operation
-
-Check for cross reference to !!DATA_OUT and !!INT_CTRL and !!INT_CTRL2 blah
-
-## Programmer Guide
-
-
-### Initialization
-
-
-### Interrupts
-
-
-
-### Debug Features
-
-
-## Implementation Guide
-
-
-## Registers
-{{% registers x }}
diff --git a/util/docgen/examples/include/inc2.md b/util/docgen/examples/include/inc2.md
deleted file mode 100644
index 0a9e37f..0000000
--- a/util/docgen/examples/include/inc2.md
+++ /dev/null
@@ -1,8 +0,0 @@
-### depth 2 include
-
-[Anchor 3]: https://google.com
-
-mumble
-* Try out [Anchor 1][] defined in outer
-
-### end depth 2 include
diff --git a/util/docgen/examples/include/included.md b/util/docgen/examples/include/included.md
deleted file mode 100644
index 89c8096..0000000
--- a/util/docgen/examples/include/included.md
+++ /dev/null
@@ -1,14 +0,0 @@
-
-### This is the **included** md file!
-
-Check from included for cross reference to !!DATA_OUT and !!INT_CTRL and !!INT_CTRL2 blah
-
-[Anchor 2]: https://github.com/mdhayter
-
-mumble
-* Try out [Anchor 1][] defined later
-* Try out [Anchor 2][] defined in include
-
-{{% include inc2.md }}
-
-### end first include
diff --git a/util/docgen/examples/ls b/util/docgen/examples/ls
deleted file mode 100755
index 66127dc..0000000
--- a/util/docgen/examples/ls
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-ls $*
diff --git a/util/docgen/examples/test_inc.md b/util/docgen/examples/test_inc.md
deleted file mode 100644
index 3873b21..0000000
--- a/util/docgen/examples/test_inc.md
+++ /dev/null
@@ -1,58 +0,0 @@
-{{% lowrisc-doc-hdr Example like first gpio }}
-{{% regfile gp.hjson }}
-
-Blah
-
-{{% toc 3 }}
-
-## Compatibility
-
-* Try out [Anchor 1][] defined in outer
-* Try out [Anchor 2][] defined in include depth 1
-* Try out [Anchor 3][] defined in include depth 2
-
-
-{{% include include/included.md }}
-
-[Anchor 1]: https://github.com/lowRisc
-
-## this include should fail
-
-{{% include no_such_file.md }}
-
-## exec include
-
-This should work since there is an exec ls in the directory
-{{% include !ls -1 errors.md errorsregs.hjson }}```
-```
-
-This should fail because command does not exist {{% include !ps au }}
-
-This should fail for trying to escape the repo {{% include !../../../../foo }}
-
-# big include
-
-{{% include !../../regtool.py --doc }}
-
-## Theory of operation
-
-Check for cross reference to !!DATA_OUT and !!INT_CTRL and !!INT_CTRL2 blah
-
-## Programmer Guide
-
-
-### Initialization
-
-
-### Interrupts
-
-
-
-### Debug Features
-
-
-## Implementation Guide
-
-
-## Registers
-{{% registers x }}
diff --git a/util/docgen/examples/test_win.md b/util/docgen/examples/test_win.md
deleted file mode 100644
index 3c9c92e..0000000
--- a/util/docgen/examples/test_win.md
+++ /dev/null
@@ -1,31 +0,0 @@
-{{% lowrisc-doc-hdr Test for register space windows }}
-{{% regfile win.hjson }}
-
-Blah
-
-{{% toc 3 }}
-
-## Compatibility
-
-## Theory of operation
-
-Check for cross reference to !!win1 and !!RDATA and !!win2 blah
-
-## Programmer Guide
-
-
-### Initialization
-
-
-### Interrupts
-
-
-
-### Debug Features
-
-
-## Implementation Guide
-
-
-## Registers
-{{% registers x }}
diff --git a/util/docgen/examples/uart.hjson b/util/docgen/examples/uart.hjson
deleted file mode 100644
index bf8e36c..0000000
--- a/util/docgen/examples/uart.hjson
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-{
-  name: "UART",
-  clock_primary: "clk_fixed",
-  bus_device: "tlul",
-  regwidth: "64",
-  registers: [
-    {name: "RDATA", desc: "UART read data",
-      swaccess: "ro", fields: [
-      {bits: "7:0", resval: "0x0"}
-    ]},
-    {name: "WDATA", desc: "UART write data", swaccess: "wo", fields: [
-      {bits: "7:0", resval: "0x0"}
-    ]},
-    {name: "NCO", desc: "Baud clock rate control", swaccess: "rw", fields: [
-      {bits: "15:0", resval: "0b0"}
-    ]},
-    {name: "CTRL", desc: "UART control register", swaccess: "rw", fields: [
-      {bits: "0", name: "TX", desc: '''
-        TX enable has a really long description that will go on over
-	several lines and really want to wrap to be seen well in the
-	source format.
-	'''
-	}
-      {bits: "1", name: "RX", desc: "RX enable"}
-      {bits: "2", name: "CTS", desc: "CTS hardware flow-control enable"}
-      {bits: "3", name: "RTS", desc: "RTS hardware flow-control enable"}
-      {bits: "4", name: "SLPBK", desc: "System loopback enable"}
-      {bits: "5", name: "LLPBK", desc: "Line loopback enable"}
-      {bits: "6", name: "RCOS", desc: "Oversample enable for RX and CTS"}
-      {bits: "7", name: "NF", desc: "RX noise filter enable"}
-      {bits: "8", name: "PARITY_EN", desc: "Parity enable"}
-      {bits: "9", name: "PARITY_ODD", desc: "1 for odd parity, 0 for even."}
-    ]}
-    {name: "ICTRL", desc: "UART Interrupt control register", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "TX", desc: "TX interrupt enable" }
-      {bits: "1", name: "RX", desc: "RX interrupt enable"}
-      {bits: "2", name: "TXO", desc: "TX overflow interrupt enable"}
-      {bits: "3", name: "RXO", desc: "RX overflow interrupt enable"}
-      {bits: "4", name: "RXF", desc: "RX frame error interrupt enable"}
-      {bits: "5", name: "RXB", desc: "RX break error interrupt enable"}
-      {bits: "7:6", name: "RXBLVL", desc: '''
-       Trigger level for rx break detection. Sets the number of character
-       times the line must be low to detect a break
-       ''',
-       enum: [
-       	       { value: "0", name: "break2", desc: "2 characters" },
-       	       { value: "1", name: "break4", desc: "4 characters" },
-       	       { value: "2", name: "break8", desc: "8 characters" },
-       	       { value: "3", name: "break16", desc: "16 characters" }
-	     ]
-      }
-      {bits: "8", name: "RXTO", desc: "RX timeout interrupt enable"}
-      {bits: "9", name: "RXPE", desc: "RX parity error interrupt enable"}
-    ]}
-    {name: "STATE", desc: "UART state register", swaccess: "ro",
-     fields: [
-      {bits: "0", name: "TX", desc: "TX buffer full" }
-      {bits: "1", name: "RX", desc: "RX buffer full"}
-      {bits: "2", name: "TXO", desc: "TX buffer overflow"}
-      {bits: "3", name: "RXO", desc: "RX buffer overflow"}
-      {bits: "4", name: "TXEMPTY", desc: "TX buffer empty"}
-      {bits: "5", name: "TXIDLE", desc: "TX idle"}
-      {bits: "6", name: "RXIDLE", desc: "RX idle"}
-      {bits: "7", name: "RXEMPTY", desc: "RX fifo empty"}
-    ]}
-    // I suspect STATECLR should be r0w1c or something
-    {name: "STATECLR", desc: "UART state register", swaccess: "rw",
-     fields: [
-      {bits: "19", name: "TXO", desc: "Clear TX buffer overflow"}
-      {bits: "20", name: "RXO", desc: "Clear RX buffer overflow"}
-    ]}
-    {name: "ISTATE", desc: "UART Interrupt state register", swaccess: "ro",
-     fields: [
-      {bits: "0", name: "TX", desc: "TX interrupt state" }
-      {bits: "1", name: "RX", desc: "RX interrupt state"}
-      {bits: "2", name: "TXO", desc: "TX overflow interrupt state"}
-      {bits: "3", name: "RXO", desc: "RX overflow interrupt state"}
-      {bits: "4", name: "RXF", desc: "RX frame error interrupt state"}
-      {bits: "5", name: "RXB", desc: "RX break error interrupt state"}
-      {bits: "6", name: "RXTO", desc: "RX timeout interrupt state"}
-      {bits: "7", name: "RXPE", desc: "RX parity error interrupt state"}
-    ]}
-    {name: "ISTATECLR", desc: "UART Interrupt clear register",
-     swaccess: "r0w1c",
-     fields: [
-      {bits: "0", name: "TX", desc: "Clear TX interrupt" }
-      {bits: "1", name: "RX", desc: "Clear RX interrupt"}
-      {bits: "2", name: "TXO", desc: "Clear TX overflow interrupt"}
-      {bits: "3", name: "RXO", desc: "Clear RX overflow interrupt"}
-      {bits: "4", name: "RXF", desc: "Clear RX frame error interrupt"}
-      {bits: "5", name: "RXB", desc: "Clear RX break error interrupt"}
-      {bits: "6", name: "RXTO", desc: "Clear RX timeout interrupt"}
-      {bits: "7", name: "RXPE", desc: "Clear RX parity error interrupt"}
-    ]}
-    {name: "FIFO", desc: "UART FIFO control register", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "RXRST", swaccess: "r0w1c", desc: "RX fifo reset" }
-      {bits: "1", name: "TXRST", swaccess: "r0w1c", desc: "TX fifo reset" }
-      {bits: "4:2", name: "RXILVL",
-       desc: "Trigger level for RX interrupts"
-       enum: [
-       	       { value: "0", name: "rxlvl1", desc: "1 character" },
-       	       { value: "1", name: "rxlvl4", desc: "4 characters" },
-       	       { value: "2", name: "rxlvl8", desc: "8 characters" },
-       	       { value: "3", name: "rxlvl16", desc: "16 characters" }
-       	       { value: "4", name: "rxlvl30", desc: "30 characters" }
-	       // TODO expect generator to make others reserved
-	     ]
-      }
-      {bits: "6:5", name: "TXILVL",
-       desc: "Trigger level for TX interrupts"
-       enum: [
-       	       { value: "0", name: "txlvl1", desc: "1 character" },
-       	       { value: "1", name: "txlvl4", desc: "4 characters" },
-       	       { value: "2", name: "txlvl8", desc: "8 characters" },
-       	       { value: "3", name: "txlvl16", desc: "16 characters" }
-	     ]
-      }
-    ]}
-    {name: "RFIFO", desc: "UART FIFO status register", swaccess: "ro",
-     fields: [
-      {bits: "5:0", name: "TXLVL", desc: "Current fill level of TX fifo" }
-      {bits: "11:6", name: "RXLVL", desc: "Current fill level of RX fifo" }
-    ]}
-    {name: "OVRD", desc: "UART override control register", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "TXEN", desc: "Override the TX signal" }
-      {bits: "1", name: "TXVAL", desc: "Value for TX Override" }
-      {bits: "2", name: "RTSEN", desc: "Override the RTS signal" }
-      {bits: "3", name: "RTSVAL", desc: "Value for RTS Override" }
-    ]}    
-    {name: "VAL", desc: "UART oversampled values", swaccess: "ro",
-     fields: [
-      {bits: "15:0", name: "RX", desc: '''
-       Last 16 oversampled values of RX. Most recent bit is bit 0, oldest 15.
-      ''' }
-      {bits: "31:16", name: "CTS", desc: '''
-       Last 16 oversampled values of CTS. Most recent bit is bit 16, oldest 31.
-      ''' }
-    ]}
-    {name: "RXTO", desc: "UART RX timeout control", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "EN", desc: "Enable RX timeout feature" }
-      {bits: "24:1", name: "VAL", desc: "RX timeout value in UART bit times" }
-    ]}    
-    { skipto: "0x0f00" }
-    {name: "ITCR", desc: "UART Integration test control", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "", desc: "-" }
-    ]}    
-    {name: "ITOP", desc: "UART Integration test overrides", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "TX", desc: "Drive txint when UART_ITCR asserted" }
-      {bits: "1", name: "RX", desc: "Drive rxint when UART_ITCR asserted" }
-      {bits: "2", name: "TXO", desc: "Drive txoint when UART_ITCR asserted" }
-      {bits: "3", name: "RXO", desc: "Drive rxoint when UART_ITCR asserted" }
-      {bits: "4", name: "RXF", desc: "Drive rxfint when UART_ITCR asserted" }
-      {bits: "5", name: "RXB", desc: "Drive rxbint when UART_ITCR asserted" }
-      {bits: "6", name: "RXTO", desc: "Drive rxtoint when UART_ITCR asserted" }
-      {bits: "7", name: "RXPE", desc: "Drive rxpeint when UART_ITCR asserted" }
-    ]}
-    {name: "DVREG", desc: "DV-accessible test register", swaccess: "rw",
-     fields: [
-      {bits: "56:0", name: "", desc: "-" }
-    ]}    
-  ]
-}
diff --git a/util/docgen/examples/uart.md b/util/docgen/examples/uart.md
deleted file mode 100644
index e0be560..0000000
--- a/util/docgen/examples/uart.md
+++ /dev/null
@@ -1,264 +0,0 @@
-{{% lowrisc-doc-hdr Simple UART }}
-{{% regfile uart.hjson }}
-
-The simple UART provides an asynchronous serial interface that can
-operate at programmable BAUD rates. The main features are:
-
-- 32 byte transmit FIFO
-- 32 byte receive FIFO
-- Programmable fractional baud rate generator
-- Hardware flow control (when enabled)
-- 8 data bits
-- optional parity bit (even or odd)
-- 1 stop bit
-
-{{% toc 3 }}
-
-## Compatibility
-
-The simple UART is compatible with the H1 Secure Microcontroller UART
-used in the Chrome OS cr50 codebase
-(https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/g/).
-The parity option has been added.
-
-## Theory of operation
-
-*TODO block diagram of UART*
-
-The UART can connect to four external pins:
-* TX: transmit data output.
-* RX: receive data input.
-* RTS: request to send flow control output. This pin is active low.
-* CTS: clear to send flow control input. This pin is active low.
-
-### Serial data format
-
-The serial line is high when idle. Characters are sent using a start
-bit (low) followed by 8 data bits sent least significant
-first. Optionally there may be a parity bit which is computed to give
-either even or odd parity. Finally there is a stop bit (high). The
-start bit for the next character may immediately follow the stop bit,
-or the line may be in the idle (high) state for some time.
-
-#### Serial waveform
-
-```wavejson
-{signal: [
-  {name:'Baud Clock',  wave: 'p...........' },
-  {name:'Data',        wave: '10========1.',
-   data: [ "lsb", "", "", "", "", "", "", "msb" ] },
-  {name:'With Parity', wave: '10=========1',
-   data: [ "lsb", "", "", "", "", "", "", "msb", "par" ] },
- ],
- head:{
-   text:'Serial Line format',
-   tick:0,
- }
-}
-```
-
-### Transmission
-
-The UART will normally format characters (add start, parity and stop
-bits) and transmit them whenever the line is idle and there is a
-character available in the transmit FIFO.
-
-If !!CTRL.CTS is set then the CTS input is checked before
-starting a transmission. If CTS is active (low) then the character is
-transmitted as usual. If CTS is inactive (high) then tranmission is
-delayed until CTS is asserted again. Note that once transmission of a
-character has started the state of the CTS line will have no effect
-until the stop bit has been transmitted.
-
-### Reception
-
-The internal clock runs at 16x the baud rate. This is used to sample
-the receive data. While the line is idle the data is sampled
-high. After the line goes low the data and parity bits are sampled in
-the middle of their bit time and the character received. The stop bit
-is checked in the middle of its bit time and must be high or a framing
-error will be reported.
-
-If there is space in the receive FIFO then the received character is
-written to the FIFO otherwise it is discarded and the RX overrun
-interrupt set. *TODO what happens if it has a parity or framing
-error, is the character added to the FIFO or not?*.
-
-For a character to be correctly recieved the local clock and the
-peer's transmit clock must drift by no more than half a bit time
-between the start of the start bit and the mid-point of the stop
-bit. Thus without parity the clocks can differ by no more than 5.2%
-(0.5 bit-times / 9.5 bit-times), and with parity they can differ by no
-more than 4.7% (0.5 bit-times / 10.5 bit-times).
-
-The stop bit in the serial line format ensures that the line will
-never be low for more than 9 (10 with parity) bit-times. If the line
-is detected low for multiple character times (configured in the
-!!ICTRL.RXBLVL field) then the receiver will detect a break
-condition and signal an interrupt. *TODO will any zero characters be
-received? Depends on answer to framing error question?*
-
-If !!CTRL.CTS is set, the receiver provides flow control by
-driving the RTS output. When the number of characters in the receive
-FIFO is below the level set in !!FIFO.RXILVL the UART will drive
-this pin low (active) to indicate it is ready to accept data. Once the
-FIFO has reached the programmed level the UART will drive the pin high
-(inactive) to stop the remote device sending more data.
-
-If !!CTRL.CTS is clear, active flow control is disabled. The UART
-will drive the RTS pin low (active) whenever its receiver is enabled
-(!!CTRL.RX set) and high (inactive) whenever the receiver is
-disabled.
-
-*TODO say something about the RX noise filter enable bit*
-
-## Programmer Guide
-
-
-### Initialization
-
-The internal clock must be configured to run at 16x the required BAUD
-rate. This is done by programming the Numerically Controlled
-Oscillator (!!NCO register). The register should be set to
-(2<sup>20</sup>*f<sub>baud</sub>)/f<sub>pclk</sub>, where
-f<sub>baud</sub> is the required baud rate and f<sub>pclk</sub> is the
-peripheral clock provided to the UART.
-
-Care should be taken not to overflow the registers during the baud
-rate setting, 64-bit arithmetic may need to be forced. For example:
-
-```c
-	long long setting = (16 * (1 << UART_NCO_WIDTH) *
-			     (long long)CONFIG_UART_BAUD_RATE / PCLK_FREQ);
-	/* set frequency */
-	GR_UART_NCO(uart) = setting;
-```
-
-During initialization the !!FIFO register should be written to
-clear the FIFOs and set the trigger levels for interrupt and flow
-control. This should be done before enabling the UART and flow control
-by setting the !!CTRL register.
-
-### Character FIFOs
-
-The transmit and recieve FIFOs are always used and each are always 32
-characters deep.
-
-Prior to adding a character to the transmit FIFO the !!STATE.TX
-bit can be checked to ensure there is space in the FIFO. If a
-character is written to a full FIFO then the character is discarded,
-the !!STATE.TXO bit is set and a TX overrun interrupt raised.
-
-If the receive FIFO is full when a new character is received thenthe
-!!STATE.RXO bit is set and a RX overrun interrupt raised.
-
-The overrun status is latched, so will persist to indicate characters
-have been lost, even if characters are removed from the corresponding
-FIFO. The state must be cleared by writing 1 to !!STATECLR.TXO or
-!!STATECLR.RXO.
-
-The number of characters in the FIFO selects the interrupt
-behaviour. The TX interrupt will be raised when there are fewer
-characters in the FIFO than configured in the !!FIFO.TXILVL
-field. The RX interrupt will be raised when there are the same or more
-characters in the FIFO than configured in the !!FIFO.RXILVL
-field. *TODO check I understand these levels*
-
-The number of characters currently in each FIFO can always be read
-from the !!RFIFO register.
-
-### Receive timeout
-
-The receiver timeout mechanism can raise an interrupt if the receiver
-detects the line to be idle for a long period. This is enabled and the
-timeout configured in the !!RXTO register.
-
-### Interrupts
-
-The UART has eight interrupts:
-- TX: raised if the transmit FIFO is past the trigger level
-- RX: raised if the receive FIFO is past the trigger level
-- TXOV: raised if the transmit FIFO has overflowed
-- RXOV: raised if the receive FIFO has overflowed
-- RXF: raised if a framing error has been detected on receive
-- RXB: raised if a break condition is detected on receive
-- RXTO: raised if the receiver has not received any characters in a time
-- RXPE: raised if the receiver has detected a parity error
-
-The current state of the interrupts can be read from the !!ISTATE
-register. Each interrupt has a corresponding bit in the
-!!ISTATECLR register that must be written with a 1 to clear the
-interrupt.
-
-Interrupts are enabled in the !!ICTRL register (note the bit
-assignment does not match the other registers bacuse this register
-also configurs the break condition). This registe just configures if
-the interrupt will be signalled to the system interrupt controller, it
-will not change or mask the value in the !!ISTATE register.
-
-### Debug Features
-
-There are two loopback modes that may be useful during debugging.
-
-System loopback is enabled by setting !!CTRL.SLPBK. Any
-characters written to the transmit buffer will be copied to the
-receive buffer. The state of the RX and CTS pins are ignored. Hardware
-flow control should be disabled when this mode is used.
-
-Line loopback is enabled by setting !!CTRL.LLPBK. Any data
-received on the RX pin is transmitted on the TX pin. Data is retimed
-by the peripheral clock, so this is only reliable if f<sub>pclk</sub>
-is more than twice the baud rate being received. Hardware flow
-control, the TX and RX fifos and interrupts should be disabled when
-this mode is used.
-
-Direct control of the TX pin can be done by setting the value to drive
-in the !!OVRD.TXVAL bit with the !!OVRD.TXEN bit set.  Direct control
-of the RTS pin can be done by setting the value to drive in the
-!!OVRD.RTSVAL bit with the !!OVRD.RTSEN bit set.
-
-The most recent samples from the receive and CTS pins gathered at 16x
-the baud clock can be read from the !!VAL register if
-!!CTRL.RCOS is set.
-
-Interrupts can be tested by configuring the interrupts to be raised in
-the !!ITOP register and setting the !!ITCR bit. This will
-raise the corresponding interrupts to the system. It is recommended
-the regular sources are disabled in the !!ICTRL register when
-this feature is used. *TODO is this implementation?*
-
-
-
-## Implementation Guide
-
-The toplevel of the UART has the following signals that connect to
-external pins:
-- TX data output connects to external pin
-- RX: receive data input connects to external pin
-- RTS: request to send flow control output. This pin is active
-  low. Connects to external pin.
-- CTS: clear to send flow control input. This pin is active
-  low. Connects to external pin.
-
-The following signals connect to the interrupt controller:
-- txint
-- rxint
-- txoint
-- rxoint
-- rxfint
-- rxbint
-- rxtoint
-- rxpeint
-
-A clock with some spec must be provided:
-- pckl
-
-The main register interface is an APB slave using:
-- APB signals
-
-An additional 32-bit scratch register !!DVREG is provided.
-
-The UART code has no build-time options. (Unless it does.)
-
-## Registers
-{{% registers x }}
diff --git a/util/docgen/examples/uart16550.hjson b/util/docgen/examples/uart16550.hjson
deleted file mode 100644
index c88f294..0000000
--- a/util/docgen/examples/uart16550.hjson
+++ /dev/null
@@ -1,334 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-{
-  name: "UART16550",
-  clock_primary: "clk_fixed",
-  bus_device: "tlul",
-
-  regwidth: 8,
-  registers: [
-    {name: "DATA", desc: "UART data",
-      swaccess: "rw", fields: [
-	  { bits: "7:0", resval: "x", desc: '''
-             A read returns the **bold character** in the receive buffer if
-             !!LCR.DLAB is clear, or the *italic low byte* of the ** bold
-	     divisor split over line** if
-	     !!LCR.DLAB is set.  Writes send characters to the
-	     transmitter holding
-             buffer if !!LCR.DLAB is clear, or set the low byte of the
-             divisor if DLAB in !!LCR is set.
-            '''
-	  }
-      ]
-    },
-    {name: "IER", desc: "Interrupt enable register", swaccess: "rw", fields: [
-      {bits: "0", name: "RDAE", desc: '''
-        Enable Received Data Available interrupt. If this bit is set
-        an interrupt will be raised whenever the receive FIFO contains
-        data. This reference is to a !!BOGUS register
-	'''
-      }
-      {bits: "1", name: "TXEE", desc: '''
-        Enable Transmit holding register empty interrupt. If this bit
-        is set then an interrupt will be raised whenever the
-        transmitter buffer is empty.
-	'''
-      }
-      {bits: "2", name: "RLE", desc: '''
-        Enable Receiver Line Status. If this bit is set then an
-        interrupt will be raised whenever the receive side line status
-        changes.
-	'''
-      }
-      {bits: "3", name: "MSE", desc: '''
-        Enable Modem Status interrupt. If this bit is set then an
-        interrupt will be raised whenever the modem status changes.
-	'''
-      }
-      {bits: "4", name: "SLP", desc: '''
-        If this bit is set the UART will enter sleep mode. Operation
-        will be stopped until a transition is detected on DIN, CTS_L,
-        DSR_L, DCD_L or RI_L.
-	'''
-      }
-      {bits: "5", name: "LPE", desc: '''
-        If this bit is set the UART will enter low power mode, the
-        same as sleep.
-	'''
-      }
-    ]},
-    {sameaddr: [
-	{name: "IIR", desc: "Interrupt identification register",
-	 swaccess: "ro", fields: [
-	     {bits: "0", name: "INT", resval: "1",
-	      desc: "This bit is clear if the UART is interrupting."
-	     }
-	     {bits: "2:1", name: "TYPE",
-	      desc: '''
-              If the INT bit is clear, these bits indicate the highest
-              priority pending interrupt.
-              '''
-	      enum: [
-      		 { value: "0", name: "mdm", desc: "Modem status (lowest)" },
-       		 { value: "1", name: "txe", desc: "TX holding register empty" },
-       		 { value: "2", name: "rxd", desc: "RX data available" },
-       		 { value: "3", name: "rxl", desc: "RX line status (highest)" }
-	      ]
-	     }
-	     {bits: "3", name: "TO",
-	      desc: "This bit is set if there is a timeout interrupt pending."
-	     }
-	     {bits: "5", name: "F64",
-	      desc: "Will always be clear because the FIFO is not 64 bytes."
-	     }
-	     {bits: "7:6", name: "FEN", desc: '''
-	      These bits will both be clear if the FIFO is disabled
-	      and both be set if it is enabled.
-              '''
-	     }
-	 ]}
-	{name: "FCR", desc: "FIFO Control Register",
-	 swaccess: "wo", fields: [
-	     {bits: "0", name: "FEN",
-	      desc: "This bit must be set to enable the FIFOs."
-	     }
-	     {bits: "1", name: "CRX", desc: '''
-               Writing this bit with a 1 will reset the RX fifo. The
-               bit will clear after the FIFO is reset.
-              '''
-	     }
-	     {bits: "2", name: "CTX", desc: '''
-               Writing this bit with a 1 will reset the TX fifo. The
-               bit will clear after the FIFO is reset.
-              '''
-	     }
-	     {bits: "3", name: "DMAS",
-	      desc: "DMA Mode Select. This bit is not used."
-	     }
-	     {bits: "5", name: "E64",
-	      desc: "This bit is reserved because the FIFO is not 64 bytes."
-	     }
-	     {bits: "7:6", name: "TL",
-	      desc: '''
-                These two bits set the interrupt trigger level for the
-                receive FIFO. The received data available interrupt
-                will be set when there are at least this number of
-                bytes in the receive FIFO.
-              '''
-	      enum: [
-      		 { value: "0", name: "rxlvl1", desc: "1 Byte" },
-       		 { value: "1", name: "rxlvl4", desc: "4 Bytes" },
-       		 { value: "2", name: "rxlvl8", desc: "8 bytes" },
-       		 { value: "3", name: "rxlvl14", desc: "14 bytes" }
-	      ]
-	     }
-	 ]}
-    ]}
-      {name: "LCR", desc: "Line control register", swaccess: "rw", fields: [
-       {bits: "1:0", name: "WSIZE", desc: '''
-        These two bits set the word size for both transmission and reception.
-	'''
-       enum: [
-      	   { value: "0", name: "bits5", desc: "5 bits" },
-       	   { value: "1", name: "bits6", desc: "6 bits" },
-       	   { value: "2", name: "bits7", desc: "7 bits" },
-       	   { value: "3", name: "bits8", desc: "8 bits" }
-       ]
-      }
-      {bits: "2", name: "STOP", desc: '''
-        If this bit is clear one stop bit is used. If this bit is set
-        then two stop bits are used for 6,7, and 8 bit transmission
-        and 1.5 stop bits for 5 bit transmission.
-	'''
-      }
-      {bits: "3", name: "PAR", desc: '''
-        If this bit is clear parity is not used. If this bit is set
-        then parity is added according to the PTYPE field.
-	'''
-      }
-      {bits: "5:4", name: "PTYPE", desc: '''
-        These two bits set the parity for both transmission and reception.
-	'''
-       enum: [
-      	   { value: "0", name: "parodd", desc: "Odd parity" },
-       	   { value: "1", name: "pareven", desc: "Even parity" },
-       	   { value: "2", name: "parhigh", desc: "Parity bit always 1" },
-       	   { value: "3", name: "parlow", desc: "Parity bit always 0" }
-       ]
-      }
-      {bits: "6", name: "BRKEN", desc: '''
-        If this bit is clear the line runs as normal. If set then TX
-        is forced low, sending a break condition.
-	'''
-      }
-      {bits: "7", name: "DLAB", desc: '''
-        If this bit is clear the normal registers are accessed at
-        offset 0 and 1. If set then the divisor latch can be accessed.
-	'''
-      }
-    ]},
-    {name: "MCR", desc: "Modem control register", swaccess: "rw", fields: [
-      {bits: "0", name: "FDTR", desc: '''
-        The state of this bit sets the state of the DTR pin. When
-        loopback mode is selected this drives the DSR_L input.
-	'''
-      }
-      {bits: "1", name: "FRTS", desc: '''
-        The state of this bit sets the state of the RTS_L pin. When
-        loopback mode is selected this drives the CTS_L input.
-	'''
-      }
-      {bits: "2", name: "OUT1", desc: '''
-        The state of this bit sets the state of the OUT1 signal. This
-        is only used in loopback mode when it drives the RI input.
-	'''
-      }
-      {bits: "3", name: "OUT2", desc: '''
-        The state of this bit sets the state of the OUT2 signal. This
-        is only used in loopback mode when it drives the DCD_L input.
-	'''
-      }
-      {bits: "4", name: "LOOP", desc: '''
-        This bit should be clear for normal operation. If this bit is
-        set the TX pin will go high, the handshake outputs will go
-        inactive and the receiver inputs are ignorred. Internally the
-        transmitter is looped back to the receiver, allowing testing
-        of the UART.
-	'''
-      }
-      {bits: "5", name: "AFC", desc: '''
-        If this bit is set and the FRTS bit is set the UART will
-        generate RTS based on the trigger level set for the receive
-        FIFO. (If FRTS is clear then RTS will be deasserted whatever
-        the state of this bit.) RTS will be asserted while the FIFO
-        contains fewer bytes than set in the FCR TL field. If a start
-        bit is seen while the FIFO is at or above the trigger level
-        then RTS will be deasserted. If the FIFO is not being emptied
-        one byte above the trigger level will be received, and there
-        could be one byte more to cover the source being slow to
-        respond to the RTS deassertion. In addition when this bit is
-        set the UART will only start trasmission of a character when
-        CTS is asserted.
-	'''
-      }
-
-    ]},
-    {name: "LSR", desc: "Line status register", swaccess: "ro", fields: [
-	{bits: "0", name: "DRDY", desc: '''
-           If this bit is set there is data ready to be read from the
-           receive buffer.
-	   '''
-	}
-	{bits: "1", name: "OVR", swaccess:"rc", desc: '''
-           If this bit is set then the receive FIFO has overrun and
-           data has been lost. The overflow status is raised when a
-           character is received and the FIFO is full, and cleared
-           whenever the LSR is read. Thus the OVR bit does not
-           indicate where in the data the lost character(s) happened.
-	   '''
-	}
-	{bits: "2", name: "PE", desc: '''
-           If this bit is set then the character at the head of the
-           receive FIFO (i.e. the next character to be read from the
-           receive buffer) has a parity error.
-	'''
-	}
-	{bits: "3", name: "FE", desc: '''
-           If this bit is set then the character at the head of the
-           receive FIFO (i.e. the next character to be read from the
-           receive buffer) has a framing error. The STOP bit was not
-           seen as set.
-	'''
-	}
-	{bits: "4", name: "BRK", desc: '''
-           If this bit is set then the character at the head of the
-           receive FIFO (i.e. the next character to be read from the
-           receive buffer) is zero and was the start of a line break condition.
-	   '''
-	}
-	{bits: "5", name: "THRE", resval: "1", desc: '''
-           If this bit is set the transmitter FIFO is empty (but there may
-           be a character being transmitted).
-	   '''
-      }
-	{bits: "6", name: "TEMT", resval: "1", desc: '''
-         If this bit is set the transmitter is empty. There are no
-         characters in the holding register, FIFO or currently
-         being transmitted.
-	 '''
-      }
-	{bits: "7", name: "RFE", swaccess:"rc", desc: '''
-        If this bit is set there is at least one character in the
-        receive FIFO with a parity error or framing error or break
-        condition. This bit is cleared by reading the LSR if there
-        are no subsequent errors in the FIFO.
-	'''
-      }
-    ]},
-    {name: "MSR", desc: "Modem status register", swaccess: "ro", fields: [
-	{bits: "0", name: "DCTS", swaccess:"rc", desc: '''
-          If this bit is set the CTS input has changed since this
-          register was last read. (Note that this bit is set by a
-          transition on the line. If multiple transitions have happened
-          then the velue in the CTS bit may be the same as in the
-          last read even though this bit is set.) In loopback mode a write
-          to the register with a 1 in this bit will cause the bit to be
-          set (and potentially an interrupt raised), writes of 0 are ignorred.
-	'''
-	}
-	{bits: "1", name: "DDSR", swaccess:"rc", desc: '''
-          If this bit is set the DSR input has changed since this
-          register was last read. (See note for DCTS) In loopback mode a write
-          to the register with a 1 in this bit will cause the bit to be
-          set (and potentially an interrupt raised), writes of 0 are ignorred.
-	'''
-	}
-	{bits: "2", name: "TRI", swaccess:"rc", desc: '''
-          If this bit is set a low to high transition was seen on the RI input
-          since this
-          register was last read. (See note for DCTS) In loopback mode a write
-          to the register with a 1 in this bit will cause the bit to be
-          set (and potentially an interrupt raised), writes of 0 are ignorred.
-	  '''
-	}
-	{bits: "3", name: "DDCD", swaccess:"rc", desc: '''
-          If this bit is set the DCD input has changed since this
-          register was last read. (See note for DCTS) In loopback mode a write
-          to the register with a 1 in this bit will cause the bit to be
-          set (and potentially an interrupt raised), writes of 0 are ignorred.
-	'''
-	}
-	{bits: "4", name: "CTS", desc: '''
-           This bit reflects the state of the CTS_L input. Note that since
-           CTS_L is active low, the value of this bit is the inverse of the pin.
-	   '''
-	}
-	{bits: "5", name: "DSR", desc: '''
-        This bit reflects the state of the DSR_L input. Note that since
-        DSR_L is active low, the value of this bit is the inverse of the pin.
-	'''
-      }
-      {bits: "6", name: "RI", desc: '''
-        This bit reflects the state of the RI_L input. Note that since
-        RI_L is active low, the value of this bit is the inverse of the pin.
-	In loopback mode this bit reflects the value of OUT1 in the MCR.
-        '''
-      }
-      {bits: "7", name: "DCD", desc: '''
-        This bit reflects the state of the DCD_L input. Note that since
-        DCD_L is active low, the value of this bit is the inverse of the pin.
-	In loopback mode this bit reflects the value of OUT2 in the MCR.
-	'''
-      }
-    ]},
-    {name: "SCR", desc: "Scratch register", swaccess: "rw", fields: [
-	{bits: "7:0", name: "scratch", resval: "x", desc: '''
-        This register is not used by the hardware. Software may use it
-        as a scratch register.
-	'''
-      }
-    ]},
-
-  ]
-}
diff --git a/util/docgen/examples/uart16550.md b/util/docgen/examples/uart16550.md
deleted file mode 100644
index 8fb3395..0000000
--- a/util/docgen/examples/uart16550.md
+++ /dev/null
@@ -1,280 +0,0 @@
-{{% lowrisc-doc-hdr UART with 16550 style interface }}
-{{% regfile uart16550.hjson }}
-
-The UART16550 provides an asynchronous serial interface that can
-operate at programmable BAUD rates. The main features are:
-
-- 16 byte transmit FIFO
-- 16 byte receive FIFO
-- Programmable baud rate generator
-- Hardware flow control (when enabled)
-- 5, 6, 7, or 8 data bits
-- optional parity bit (even, odd, mark or space)
-- 1 or 2 stop bits when used with 6, 7 or 8 data bits
-- 1 or 1.5 stop bits when used with 5 data bits
-
-## Compatibility
-
-The UART16550 is compatible with the de-facto standard 16550 driver
-with registers at byte offsets.
-
-
-## Theory of operation
-
-*TODO block diagram of UART*
-
-The UART can connect to eight external pins:
-* TX: transmit data output.
-* RX: receive data input.
-* RTS_L: request to send flow control output. This pin is active low.
-* CTS_L: clear to send flow control input. This pin is active low.
-* DTR_L: data terminal ready output. This pin is active low.
-* DSR_L: data set ready input. This pin is active low.
-* DCD_L: data carrier detect input.  This pin is active low.
-* RI_L: ring indicate. This pin is active low.
-
-### Baud Rate
-
-The serial line timing is based on a 16x baud rate clock. The
-programmable baud rate generator is driven by a 133.33MHz clock and
-has a 16 bit divider to generate the 16xbaud rate reference. This
-allows generation of the standard baud rates from 300 to 921600 baud
-with less than 1% error. The divisor is accessed by setting the DLAB
-bit in the line control register which makes the low and high parts of
-the divisor value available for read and write through the byte
-registers at offset 0 (low byte of divisor)and 1 (high byte). Writing
-either of the divisor registers causes the divider counter to be
-reloaded.
-
-Required Baud | Divisor | Actual Baud | Error
---------------|---------|-------------|------
-B |D = INT(0.5 + 133.33MHz/(16*B)) | A = (133.33MHz/D)/16 | (A-B)/B
-300    | 27778 | 300       | 0%
-600    | 13889 | 600.04    | 0.01%
-1200   | 6944  | 1200.08   | 0.01%
-1800   | 4630  | 1799.86   | -0.01%
-2400   | 3472  | 2400.15   | 0.01%
-4800   | 1736  | 4800.31   | 0.01%
-9600   | 868   | 9600.61   | 0.01%
-19200  | 434   | 19201.23  | 0.01%
-38400  | 217   | 38402.46  | 0.01%
-57600  | 145   | 57471.26  | 0.47%
-115200 | 72    | 115740.74 | 0.47%
-230400 | 36    | 231481.48 | 0.47%
-460800 | 18    | 462962.96 | 0.47%
-921600 | 9     | 925925.92 | 0.47%
-
-If the baud rate divisor is set to zero the baud rate clock is stopped
-and the UART will be disabled, this is the default. The baud rate
-clock is automatically stopped to save power when the UART is idle.
-
-### Serial data format
-
-The serial line is high when idle. Characters are sent using a start
-bit (low) followed by 5, 6, 7 or 8 data bits sent least significant
-first. Optionally there may be a parity bit which is computed to give
-either even or odd parity or may be always high or always low. Finally
-there is a stop sequence during which the line is high or one or two
-(1.5 for 5 bit characters) bit times. The start bit for the next
-character may immediately follow the stop sequence, or the line may be
-in the idle (high) state for some time. The data format and (for
-reference) the baud clock are illustrated for the different number of
-data bits with no parity and a single stop bit, and for 8 data bits
-with parity. The line could go idle (high) or the next character start
-after the stop bit where "next" is indicated. All formatting
-parameters are controlled in the !!LCR.
-
-```wavejson
-{signal: [
-  {name:'Baud Clock',  wave: 'p...........' },
-  {name:'Data 8 bit',        wave: '10========1=',
-   data: [ "lsb", "", "", "", "", "", "", "msb", "next" ] },
-  {name:'Data 7 bit',        wave: '10=======1=.',
-   data: [ "lsb", "", "", "", "", "", "msb", "next" ] },
-  {name:'Data 6 bit',        wave: '10======1=..',
-   data: [ "lsb", "", "", "", "", "msb", "next" ] },
-  {name:'Data 5 bit',        wave: '10=====1=...',
-   data: [ "lsb", "", "", "", "msb", "next" ] },
-  {name:'8 with Parity', wave: '10=========1',
-   data: [ "lsb", "", "", "", "", "", "", "msb", "par" ] },
- ],
- head:{
-   text:'Serial Line format (one stop bit)',
-   tock:-1,
- }
-}
-```
-
-The data formatting ensures that in normal operation the line cannot
-be low for more than the number of data bits plus two (low start bit
-plus all zero character plus even or low parity bit) before the stop
-sequence forces the line high. If the line remains low for longer than
-this time the condition is known as a Break. The uart can be set to
-generate a (continuous) break on its output line by setting BrkEn in
-the !!LCR. Detection of a break is signalled by reception of a
-character containing all zeros that is accompanied by the Break Detect
-Flag.
-
-### Serial Data Reception
-
-The UART detect the RX line transitioning from high to low as the
-start of a potential reception. The line is checked after half a bit
-time (8 cycles of the 16xbaud rate clock) and if still low then a
-start bit is detected. Every bit-time (16 cycles of the 16x baud rate
-clock) the data is sampled. One additional bit is sampled following
-the data and parity bits. This should be the stop bit and should
-therefore be set. If the line is detected low when the stop bit is
-expected then the data is still received but is marked with a framing
-error (note that only one bit is checked even if the stop sequence is
-set to two bits). If parity is enabled and the bit does not match the
-expected value then the received character is marked with a parity
-error.
-
-### Serial Data Transmission
-
-The UART will normally format characters (add start, parity and stop
-bits) and transmit them whenever characters are available to be sent
-and the line is idle. However, setting the AFC bit in the !!MCR
-enables automatic flow control. With this setting the transmitter will
-only start to send a character if the CTS_L line is asserted
-(i.e. low) indicating that the peer device is able to receive data.
-
-### Interface FIFOs
-
-The interface has a FIFO to hold characters waiting to be transmitted
-and a FIFO to hold characters that have been received but not yet read
-by software. These FIFOs are 16 characters deep. By default the FIFOs
-are disabled (effectively one character deep) and should be enabled by
-setting the FEN bit in the FIFO Control Register. Note that when the
-FEN bit is set any character that is currently in the holding register
-will be transmitted before the FIFO is enabled (this was not the case
-prior to revision 16 of the UART where it was advised to check the
-TEMT bit in the LSR to ensure there are no characters in-flight when
-the FIFO is enabled).
-
-Writes to the Data Register when the Transmit Holding Register Empty
-(THRE) status bit is set will add characters to the transmit
-FIFO. This status bit will be clear when the FIFO is full, and any
-writes to the Data Register will be discarded.
-
-Reads from the Data Register will return the next received character
-and will remove it from the receive FIFO. Prior to reading the Data
-Register a read should be done of the Line Status Register which will
-indicate if there is data available and give the error flags that
-accompany the character at the head of the FIFO. (The error flags flow
-through the FIFO with their corresponding character.)
-
-Once the FIFOs are enabled the TL field in the FCR can be used to
-configure the number of characters that must bein the receive FIFO to
-trigger two events:
-
-1. The receive data available interrupt is raised (if the FIFO is
-   disabled this is done when a single character is received).
-
-2. If automatic flow control is enabled the RTS_L output is deasserted
-   (i.e. set high) on reception of a start bit.
-
-### Modem/Handshake Signals
-
-The UART has two output lines (RTS\_L and DTR\_L) and four input lines
-(CTS\_L, DSR\_L, DCD\_L and RI\_L) that can be used for modem
-control. However, only the RTS\_L output and CTS\_L input are given
-dedicated pins. The other lines are shared with GPIO signals and the
-GPIO configuration register must be set correctly to enable their
-use. (See section on the GPIO pins.)
-
-The state of the input signals can be read in the Modem Status
-Register which also reports if any of the lines have changed since the
-previous read of the register. Detection of a change in state can
-generate an interrupt. The state of the output lines can be set in the
-Modem Control Register.
-
-If automatic flow control is enabled then the hardware will control
-the RTS\_L output and use the state of the CTS\_L input. RTS\_L will be
-asserted whenever the receive FIFO is full to the threshold level set
-in the TL field of the FIFO Control Register and a start bit is
-detected. RTS\_L will be deasserted whenever the receive FIFO is below
-the threshold. The transmitter will check the CTS\_L signal prior to
-sending a character and will wait for CTS\_L to be asserted before
-starting the character (once a character has been started it will be
-completed before the CTS_L is checked again).
-
-
-### Interrupts and powerdown
-
-The UART can generate an interrupt to the CPU. The Interrupt Enable
-Register configures which UART events cause the interrupt to be raised
-and the Interrupt Identification Register allows detection of the
-cause of the interrupt.  In addition to the normal UART register
-controls, the interrupt may be disabled by setting the intd control
-bit in the PCI header Command register and the state of the interrupt
-may be detected in the is bit of the PCI header Status register. The
-interrupt source number that the UART will use can be read as the
-default value in the iline field of the PCI header.
-
-The UART may be forced into a low power mode by setting either or both
-of the SLP and LPE bits in the Interrupt Enable Register.
-
-### Scratch Register
-
-The UART contains an 8 bit read/write register that is not used by the
-hardware. Software may use this register as it sees fit. The value in
-the scratch register is unpredictable following a reset.
-
-Testing cross reference to !!DATA (or with punctuation !!DATA). The
-strange case will be !!LCR. Which is a different period than in
-!!LCR.DLAB or could be used twice in !!LCR.DLAB. How about
-!!LCR-!!DATA? Phew!
-
-## Programmer Guide
-
-
-### Initialization
-
-The baud rate should be set as previously outlined to enable the UART.
-
-### Interrupts
-
-The UART raises a single interrupt to the system based on the four
-sources that can be enabled in !!IER:
-
-- TXEE: raised if the transmit buffer is empty
-- RDAE: raised if received data is available (if the FIFO is enabled the
-  TL field in the FCR sets the number of characters in the FIFO before
-  this is raised)
-- RLE: The receiver line status has changed
-- MSE: The modem status has changed
-
-
-### Debug Features
-
-A loopback mode can be enabled. In this the output serial data is
-internally looped back to the receiver and the output control lines
-(and two addition signals) are looped back to the four handshake
-inputs. This allows software testing. In this mode the output pins
-will be in their inactive state (i.e. high).
-
-
-## Implementation Guide
-
-The toplevel of the UART has the following signals that connect to
-external pins:
-- TX data output connects to external pin
-- RX: receive data input connects to external pin
-- RTS_L: request to send flow control output. This pin is active
-  low. Connects to external pin.
-- CTS_L: clear to send flow control input. This pin is active
-  low. Connects to external pin.
-- DTR_L: data terminal ready output. This pin is active low.
-- DSR_L: data set ready input. This pin is active low.
-- DCD_L: data carrier detect input.  This pin is active low.
-- RI_L: ring indicate. This pin is active low.
-
-The int signal connects to the interrupt controller.
-
-The 133.33MHz peripheral clock is connected to pclk.
-
-The main register interface is connected on the I/O ring.
-
-## Registers
-{{% registers x }}
diff --git a/util/docgen/examples/uartcfg.hjson b/util/docgen/examples/uartcfg.hjson
deleted file mode 100644
index 8f227d6..0000000
--- a/util/docgen/examples/uartcfg.hjson
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-{
-  name: "uart",
-  clock_primary: "clk_fixed",
-  bus_device: "tlul",
-  bus_host: "none",
-  available_input_list: [
-    { name: "rx", desc: "Serial receive bit" }
-  ],
-  available_output_list: [
-    { name: "tx", desc: "Serial transmit bit" }
-  ],
-  interrupt_list: [
-    { name: "tx_watermark",  desc: "raised if the transmit FIFO is past the programmed highwater mark."}
-    { name: "rx_watermark",  desc: "raised if the receive FIFO is past the programmed highwater mark."}
-    { name: "tx_overflow",   desc: "raised if the transmit FIFO has overflowed."}
-    { name: "rx_overflow",   desc: "raised if the receive FIFO has overflowed."}
-    { name: "rx_frame_err",  desc: "raised if a framing error has been detected on receive."}
-    { name: "rx_break_err",  desc: "raised if break condition has been detected on receive."}
-    { name: "rx_timeout",    desc: "raised if RX FIFO has characters remaining inFIFO without being retrieved for the programmed time period."}
-    { name: "rx_parity_err", desc: "raised if the receiver has detected a parity error."}
-  ],
-
-  regwidth: "32",
-  registers: [
-    { name: "CTRL",
-      desc: "UART control register",
-      swaccess: "rw",
-      hwaccess: "hro",
-      fields: [
-        { bits: "0",
-          name: "TX",
-          desc: "TX enable"
-        }
-        { bits: "1",
-          name: "RX",
-          desc: "RX enable"
-        }
-        { bits: "2",
-          name: "NF",
-          desc: "RX noise filter enable"
-        }
-        { bits: "4",
-          name: "SLPBK",
-          desc: '''System loopback enable.
-
-                If this bit is turned on, any outgoing bits to TX are received through RX.
-                See Block Diagram.
-                '''
-        }
-        { bits: "5",
-          name: "LLPBK",
-          desc: '''Line loopback enable.
-
-                If this bit is turned on, incoming bits are forwarded to TX for testing purpose.
-                See Block Diagram.
-                '''
-        }
-        { bits: "6",
-          name: "PARITY_EN",
-          desc: "If true, parity is enabled in both RX and TX directions."
-        }
-        { bits: "7",
-          name: "PARITY_ODD",
-          desc: "If PARITY_EN is true, this determines the type, 1 for odd parity, 0 for even."
-        }
-        { bits: "9:8",
-          name: "RXBLVL",
-          desc: '''
-                Trigger level for RX break detection. Sets the number of character
-                times the line must be low to detect a break.
-                ''',
-          enum: [
-            { value: "0",
-              name: "break2",
-              desc: "2 characters"
-            },
-            { value: "1",
-              name: "break4",
-              desc: "4 characters"
-            },
-            { value: "2",
-              name: "break8",
-              desc: "8 characters"
-            },
-            { value: "3",
-              name: "break16",
-              desc: "16 characters"
-            }
-          ]
-        }
-        { bits: "31:16",
-          name: "NCO",
-          desc: "BAUD clock rate control."
-        }
-      ]
-    },
-    { name:     "STATUS"
-      desc:     "UART live status register"
-      swaccess: "ro"
-      hwaccess: "hrw"
-      hwext:    "true"
-      hwre:     "true"
-      fields: [
-        { bits: "0"
-          name: "TXFULL"
-          desc: "TX buffer is full"
-        }
-        { bits: "1"
-          name: "RXFULL"
-          desc: "RX buffer is full"
-        }
-        { bits: "2"
-          name: "TXOVERFLOW"
-          desc: "TX buffer overflow"
-        }
-        { bits: "3"
-          name: "RXOVERFLOW"
-          desc: "RX buffer overflow"
-        }
-        { bits: "4"
-          name: "TXEMPTY"
-          desc: "TX FIFO is empty"
-        }
-        { bits: "5"
-          name: "TXIDLE"
-          desc: "TX is idle"
-        }
-        { bits: "6"
-          name: "RXIDLE"
-          desc: "RX is idle"
-        }
-        { bits: "7"
-          name: "RXEMPTY"
-          desc: "RX FIFO is empty"
-        }
-      ]
-    }
-    { name: "RDATA",
-      desc: "UART read data",
-      swaccess: "ro",
-      hwaccess: "hrw",
-      hwext: "true",
-      hwre: "true",
-      fields: [
-        { bits: "7:0" }
-      ]
-    }
-    { name: "WDATA",
-      desc: "UART write data",
-      swaccess: "wo",
-      hwaccess: "hro",
-      hwqe: "true",
-      fields: [
-        { bits: "7:0" }
-      ]
-    }
-    { name: "FIFO_CTRL",
-      desc: "UART FIFO control register",
-      swaccess: "rw",
-      hwaccess: "hrw",
-      hwqe:     "true",
-      fields: [
-        { bits: "0",
-          name: "RXRST",
-          desc: "RX fifo reset"
-        }
-        { bits: "1",
-          name: "TXRST",
-          desc: "TX fifo reset"
-        }
-        { bits: "4:2",
-          name: "RXILVL",
-          desc: "Trigger level for RX interrupts",
-          enum: [
-            { value: "0",
-              name: "rxlvl1",
-              desc: "1 character"
-            },
-            { value: "1",
-              name: "rxlvl4",
-              desc: "4 characters"
-            },
-            { value: "2",
-              name: "rxlvl8",
-              desc: "8 characters"
-            },
-            { value: "3",
-              name: "rxlvl16",
-              desc: "16 characters"
-            },
-            { value: "4",
-              name: "rxlvl30",
-              desc: "30 characters"
-            },
-            // TODO expect generator to make others reserved
-          ]
-        }
-        { bits: "6:5",
-          name: "TXILVL",
-          desc: "Trigger level for TX interrupts",
-          enum: [
-            { value: "0",
-              name: "txlvl1",
-              desc: "1 character"
-            },
-            { value: "1",
-              name: "txlvl4",
-              desc: "4 characters"
-            },
-            { value: "2",
-              name: "txlvl8",
-              desc: "8 characters"
-            },
-            { value: "3",
-              name: "txlvl16",
-              desc: "16 characters"
-            }
-          ]
-        }
-      ]
-    }
-    { name: "FIFO_STATUS",
-      desc: "UART FIFO status register",
-      swaccess: "ro",
-      hwaccess: "hwo",
-      hwext: "true",
-      fields: [
-        { bits: "4:0",
-          name: "TXLVL",
-          desc: "Current fill level of TX fifo"
-        }
-        { bits: "10:6",
-          name: "RXLVL",
-          desc: "Current fill level of RX fifo"
-        }
-      ]
-    }
-    { name: "OVRD",
-      desc: "UART override control register",
-      swaccess: "rw",
-      hwaccess: "hro",
-      fields: [
-        { bits: "0",
-          name: "TXEN",
-          desc: "Override the TX signal"
-        }
-        { bits: "1",
-          name: "TXVAL",
-          desc: "Value for TX Override"
-        }
-      ]
-    }
-    { name: "VAL",
-      desc: "UART oversampled values",
-      swaccess: "ro",
-      hwaccess: "hwo",
-      hwext:    "true",
-      fields: [
-        { bits: "15:0",
-          name: "RX",
-          desc: '''
-                Last 16 oversampled values of RX. Most recent bit is bit 0, oldest 15.
-                '''
-        }
-      ]
-    }
-    { name: "TIMEOUT_CTRL",
-      desc: "UART RX timeout control",
-      swaccess: "rw",
-      hwaccess: "hro",
-      fields: [
-        { bits: "23:0",
-          name: "VAL",
-          desc: "RX timeout value in UART bit times"
-        }
-        { bits: "31",
-          name: "EN",
-          desc: "Enable RX timeout feature"
-        }
-      ]
-    }
-  ]
-}
diff --git a/util/docgen/examples/uartcfg.md b/util/docgen/examples/uartcfg.md
deleted file mode 100644
index 2ac94e9..0000000
--- a/util/docgen/examples/uartcfg.md
+++ /dev/null
@@ -1,309 +0,0 @@
-{{% lowrisc-doc-hdr UART HWIP Technical Specification }}
-{{% regfile uartcfg.hjson}}
-
-{{% section1 Overview }}
-
-This document specifies UART hardware IP functionality. This module
-conforms to the
-[Comportable guideline for peripheral device functionality.](../../../doc/rm/comportability_specification.md)
-See that document for integration overview within the broader
-top level system.
-
-{{% toc 3 }}
-
-{{% section2 Features }}
-
-- 2-pin full duplex external interface
-- 8-bit data word, optional even or odd parity bit per byte
-- 1 stop bit
-- 32 x 8b RX buffer
-- 32 x 8b TX buffer
-- Programmable baud rate
-- Interrupt for overflow, frame error, parity error, break error, receive
-  timeout
-
-{{% section2 Description }}
-
-The UART module is a serial-to-parallel receive (RX) and parallel-to-serial
-(TX) full duplex design intended to communicate to an outside device, typically
-for basic terminal-style communication. It is programmed to run at a particular
-BAUD rate and contains only a transmit and receive signal to the outside world,
-i.e. no synchronizing clock. The programmable BAUD rate guarantees to be met up
-to 1Mbps.
-
-{{% section2 Compatibility }}
-
-The UART is compatible with the feature set of H1 Secure Microcontroller UART as
-used in the [Chrome OS cr50][chrome-os-cr50] codebase. Additional features such
-as parity have been added.
-
-[chrome-os-cr50]: https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/g/
-
-{{% section1 Theory of Operations }}
-
-{{% section2 Block Diagram }}
-
-![UART Block Diagram](block_diagram.svg)
-
-{{% section2 Hardware Interfaces }}
-
-{{% hwcfg uart}}
-
-{{% section2 Design Details }}
-
-### Serial interface (both directions)
-
-TX/RX serial lines are high when idle. Data starts with START bit (1-->0)
-followed by 8 data bits. Least significant bit is sent first. If parity feature
-is turned on, at the end of the data bit, odd or even parity bit follows then
-STOP bit completes one byte data transfer.
-
-```wavejson
-{
-  signal: [
-    { name: 'Baud Clock',     wave: 'p............'                                                        },
-    { name: 'tx',             wave: '10333333331..', data: [ "lsb", "", "", "", "", "", "", "msb" ]        },
-    { name: 'Baud Clock',     wave: 'p............'                                                        },
-    { name: 'tx (w/ parity)', wave: '103333333341.', data: [ "lsb", "", "", "", "", "", "", "msb", "par" ] },
-  ],
-  head: {
-    text: 'Serial Transmission Frame',
-  },
-  foot: {
-    text: 'start bit ("0") at cycle -1, stop bit ("1") at cycle 8, or after parity bit',
-    tock: -2
-  },
-  foot: {
-    text: [
-      'tspan',
-        ['tspan', 'start bit '],
-        ['tspan', {class:'info h4'}, '0'],
-        ['tspan', ' at cycle -1, stop bit '],
-        ['tspan', {class:'info h4'}, '1'],
-        ['tspan', ' at cycle 8, or at cycle 9 after parity bit'],
-      ],
-    tock: -2,
-  }
-}
-```
-
-### Transmission
-
-A write to !!WDATA enqueues a data byte into the 32 depth write
-FIFO, which triggers the transmit module to start UART TX serial data
-transfer. The TX module dequeues the byte from the FIFO and shifts it
-bit by bit out to the UART TX pin when BAUD tick is asserted.
-
-### Reception
-
-The RX module samples the RX input pin with 16x oversampled BAUD
-clock. After it detects START bit, RX module gathers incoming serial
-bits into one byte data and pushes to 32 depth RX FIFO if it receives
-optional parity bit and correct STOP bit.  These pushed data can be read
-out by reading !!RDATA register.
-
-### Interrupts
-
-UART module has a few interrupts including general data flow interrupts
-and unexpected event interrupts.
-
-If the TX or RX FIFO hits the designated depth of entries, interrupts
-`tx_watermark` or `rx_watermark` are raised to inform FW.  FW can
-configure the watermark value via registers !!FIFO_CTRL.RXILVL or
-!!FIFO_CTRL.TXILVL .
-
-If either FIFO receives an additional write request when its FIFO is full,
-the interrupt `tx_overflow` or `rx_overflow` is asserted and the character
-is dropped.
-
-The `rx_frame_err` interrupt is triggered if RX module receives the
-`START` bit and series of data bits but did not detect `STOP` bit (`1`).
-
-```wavejson
-{
-  signal: [
-    { name: 'Baud Clock',        wave: 'p............'                                                 },
-    { name: 'rx',                wave: '10333333330..', data: [ "lsb", "", "", "", "", "", "", "msb" ] },
-    {},
-    { name: 'intr_rx_frame_err', wave: '0..........1.'},
-  ],
-  head: {
-    text: 'Serial Receive with Framing Error',
-  },
-  foot: {
-    text: [
-      'tspan',
-        ['tspan', 'start bit '],
-        ['tspan', {class:'info h4'}, '0'],
-        ['tspan', ' at cycle -1, stop bit '],
-        ['tspan', {class:'error h4'}, '1'],
-        ['tspan', ' missing at cycle 8'],
-      ],
-    tock: -2,
-  }
-}
-```
-
-The `rx_break_err` interrupt is triggered if a break condition has
-been detected. A break condition is defined as a programmable number
-of characters (via !!CTRL.RXBLVL, either 2, 4, 8, or 16) all equal to
-`0` during a frame error. This typically indicates that the UART is not
-being driven at this time.
-
-The `rx_timeout` interrupt is triggered when the RX FIFO has data sitting
-in it without software reading it for a programmable number of bit times
-(with baud rate clock as reference, programmable via !!TIMEOUT_CTRL). This
-is used to alert software that it has data still waiting in the FIFO that
-has not been handled yet. The timeout counter is reset whenever software
-reads a character from the FIFO, or if a new character is received from
-the line.
-
-The `rx_parity_err` interrupt is triggered if parity is enabled and
-the RX parity bit does not match the expected polarity as programmed
-in !!CTRL.PARITY_ODD.
-
-{{% section1 Programmers Guide }}
-
-{{% section2 Initialization }}
-
-The following code snippet shows initializing the UART to a programmable
-baud rate, clearing the RX and TX FIFO, setting up the FIFOs for interrupt
-levels, and enabling some interrupts. The NCO register controls the baud
-rate, and should be set to `(2^20*baud)/freq`, where `freq` is the fixed
-clock frequency. The UART uses `clock_primary` as a clock source.
-
-$$ NCO = {{2^{20} * f_{baud}} \over {f_{pclk}}} $$
-
-```cpp
-#define CLK_FIXED_FREQ_MHZ 48
-
-void uart_init(int baud) {
-  // set baud rate. NCO = baud * 2^20 / clock_freq =~ baud / freq_mhz
-  int setting = baud / CLK_FIXED_FREQ_MHZ;
-  *UART_CTRL_NCO_REG = setting;
-
-  // clear FIFOs and set up to interrupt on any RX, half-full TX
-  *UART_FIFO_CTRL_REG =
-      UART_FIFO_CTRL_RXRST                 | // clear both FIFOs
-      UART_FIFO_CTRL_TXRST                 |
-      (UART_FIFO_CTRL_RXILVL_RXFULL_1 <<3) | // intr on RX 1 character
-      (UART_FIFO_CTRL_TXILVL_TXFULL_16<<5) ; // intr on TX 16 character
-
-  // enable only RX, overflow, and error interrupts
-  *UART_INTR_ENABLE_REG =
-      UART_INTR_ENABLE_RX_WATERMARK_MASK  |
-      UART_INTR_ENABLE_TX_OVERFLOW_MASK   |
-      UART_INTR_ENABLE_RX_OVERFLOW_MASK   |
-      UART_INTR_ENABLE_RX_FRAME_ERR_MASK  |
-      UART_INTR_ENABLE_RX_PARITY_ERR_MASK;
-
-  // at the processor level, the UART interrupts should also be enabled
-}
-```
-
-{{% section2 Common Examples }}
-
-The following code shows the steps to transmit a string of characters.
-
-```cpp
-int uart_tx_rdy() {
-  return ((*UART_FIFO_STATUS_REG & UART_FIFO_STATUS_TXLVL_MASK) == 32) ? 0 : 1;
-}
-
-void uart_send_char(char val) {
-  while(!uart_tx_rdy()) {}
-  *UART_WDATA_REG = val;
-}
-
-void uart_send_str(char *str) {
-  while(*str != \0) {
-    uart_send_char(*str++);
-}
-```
-
-Do the following to receive a character, with -1 returned if RX is empty.
-
-```cpp
-int uart_rx_empty() {
-  return ((*UART_FIFO_STATUS_REG & UART_FIFO_STATUS_RXLVL_MASK) ==
-          (0 << UART_FIFO_STATUS_RXLVL_LSB)) ? 1 : 0;
-}
-
-char uart_rcv_char() {
-  if(uart_rx_empty())
-    return 0xff;
-  return *UART_RDATA_REG;
-}
-```
-
-{{% section2 Interrupt Handling }}
-
-The code below shows one example of how to handle all UART interrupts
-in one service routine.
-
-```cpp
-void uart_interrupt_routine() {
-  volatile uint32 intr_state = *UART_INTR_STATE_REG;
-  uint32 intr_state_mask = 0;
-  char uart_ch;
-  uint32 intr_enable_reg;
-
-  // Turn off Interrupt Enable
-  intr_enable_reg = *UART_INTR_ENABLE_REG;
-  *UART_INTR_ENABLE_REG = intr_enable_reg & 0xFFFFFF00; // Clr bits 7:0
-
-  if (intr_state & UART_INTR_STATE_RX_PARITY_ERR_MASK) {
-    // Do something ...
-
-    // Store Int mask
-    intr_state_mask |= UART_INTR_STATE_RX_PARITY_ERR_MASK;
-  }
-
-  if (intr_state & UART_INTR_STATE_RX_BREAK_ERR_MASK) {
-    // Do something ...
-
-    // Store Int mask
-    intr_state_mask |= UART_INTR_STATE_RX_BREAK_ERR_MASK;
-  }
-
-  // .. Frame Error
-
-  // TX/RX Overflow Error
-
-  // RX Int
-  if (intr_state & UART_INTR_STATE_RX_WATERMARK_MASK) {
-    while(1) {
-      uart_ch = uart_rcv_char();
-      if (uart_ch == 0xff) break;
-      uart_buf.append(uart_ch);
-    }
-    // Store Int mask
-    intr_state_mask |= UART_INTR_STATE_RX_WATERMARK_MASK;
-  }
-
-  // Clear Interrupt State
-  *UART_INTR_STATE_REG = intr_state_mask;
-
-  // Restore Interrupt Enable
-  *UART_INTR_ENABLE_REG = intr_enable_reg;
-}
-```
-
-One use of the `rx_timeout` interrupt is when the !!FIFO_CTRL.RXILVL
-is set greater than one, so an interrupt is only fired when the fifo
-is full to a certain level. If the remote device sends fewer than the
-watermark number of characters before stopping sending (for example it
-is waiting an acknowledgement) then the usual `rx_watermark` interrupt
-would not be raised. In this case an `rx_timeout` would generate an
-interrupt that allows the host to read these additional characters. The
-`rx_timeout` can be selected based on the worst latency experienced by a
-character. The worst case latency experienced by a character will happen
-if characters happen to arrive just slower than the timeout: the second
-character arrives just before the timeout for the first (resetting the
-timer), the third just before the timeout from the second etc. In this
-case the host will eventually get a watermark interrupt, this will happen
-`((RXILVL - 1)*timeout)` after the first character was received.
-
-{{% section2 Register Table }}
-
-{{% registers x }}
diff --git a/util/docgen/examples/win.hjson b/util/docgen/examples/win.hjson
deleted file mode 100644
index 9d228d1..0000000
--- a/util/docgen/examples/win.hjson
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-{
-  name: "WIND",
-  clock_primary: "clk_fixed",
-  bus_device: "tlul",
-
-  regwidth: "32",
-  registers: [
-    {name: "RDATA", desc: "UART read data",
-      swaccess: "ro", fields: [
-      {bits: "7:0", resval: "0x0"}
-    ]},
-    {name: "WDATA", desc: "UART write data", swaccess: "wo", fields: [
-      {bits: "7:0", resval: "0x0"}
-    ]},
-    {window: {
-    	     name: "win1"
-	     items: "64"
-	     swaccess: "rw"
-	     desc: '''
-	     	   A simple 256 byte window that should get aligned.
-		   It references !!RDATA and ** *bold italcs* **
-		   For testing (it also references !!WDATA) and !!NCO1.
-		   '''
-	}
-    },
-    {name: "NCO", desc: "Baud clock rate control", swaccess: "rw", fields: [
-      {bits: "15:0", resval: "0b0"}
-    ]},
-    {window: {
-    	     name: "win2"
-	     items: "15"
-	     validbits: "16"
-	     byte-write: "True"
-	     noalign: "True"
-	     swaccess: "rw1c"
-	     desc: '''
-	     	   A 60 byte window that does not get aligned.
-		   Should generate warnings
-		   '''
-	}
-    },
-    {name: "NCO1", desc: "Baud clock rate control", swaccess: "rw", fields: [
-      {bits: "15:0", resval: "0b0"}
-    ]},
-    {window: {
-    	     name: "win3"
-	     items: "15"
-	     validbits: "16"
-	     byte-write: "True"
-	     unusual: "True"
-	     swaccess: "rw1c"
-	     desc: '''
-	     	   A 60 byte window that does get aligned.
-		   Marked unusual so no warnings
-		   '''
-	}
-    },
-    {name: "CTRL", desc: "UART control register", swaccess: "rw", fields: [
-      {bits: "0", name: "TX", desc: '''
-        TX enable has a really long description that will go on over
-	several lines and really want to wrap to be seen well in the
-	source format.
-	'''
-	}
-      {bits: "1", name: "RX", desc: "RX enable"}
-      {bits: "2", name: "CTS", desc: "CTS hardware flow-control enable"}
-      {bits: "3", name: "RTS", desc: "RTS hardware flow-control enable"}
-      {bits: "4", name: "SLPBK", desc: "System loopback enable"}
-      {bits: "5", name: "LLPBK", desc: "Line loopback enable"}
-      {bits: "6", name: "RCOS", desc: "Oversample enable for RX and CTS"}
-      {bits: "7", name: "NF", desc: "RX noise filter enable"}
-      {bits: "8", name: "PARITY_EN", desc: "Parity enable"}
-      {bits: "9", name: "PARITY_ODD", desc: "1 for odd parity, 0 for even."}
-    ]}
-    {window: {
-    	     name: "win4"
-	     items: "16"
-	     validbits: "16"
-	     byte-write: "True"
-	     swaccess: "rw"
-	     desc: '''
-	     	   A simple 64 byte window that should get aligned.
-		   '''
-	}
-    },
-    {window: {
-    	     name: "win5"
-	     items: "16"
-	     validbits: "16"
-	     byte-write: "True"
-	     swaccess: "rw"
-	     desc: '''
-	     	   A simple 64 byte window that should immediately follow.
-		   '''
-	}
-    },
-    {name: "ICTRL", desc: "UART Interrupt control register", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "TX", desc: "TX interrupt enable" }
-      {bits: "1", name: "RX", desc: "RX interrupt enable"}
-      {bits: "2", name: "TXO", desc: "TX overflow interrupt enable"}
-      {bits: "3", name: "RXO", desc: "RX overflow interrupt enable"}
-      {bits: "4", name: "RXF", desc: "RX frame error interrupt enable"}
-      {bits: "5", name: "RXB", desc: "RX break error interrupt enable"}
-      {bits: "7:6", name: "RXBLVL", desc: '''
-       Trigger level for rx break detection. Sets the number of character
-       times the line must be low to detect a break
-       ''',
-       enum: [
-       	       { value: "0", name: "break2", desc: "2 characters" },
-       	       { value: "1", name: "break4", desc: "4 characters" },
-       	       { value: "2", name: "break8", desc: "8 characters" },
-       	       { value: "3", name: "break16", desc: "16 characters" }
-	     ]
-      }
-      {bits: "8", name: "RXTO", desc: "RX timeout interrupt enable"}
-      {bits: "9", name: "RXPE", desc: "RX parity error interrupt enable"}
-    ]}
-    {name: "STATE", desc: "UART state register", swaccess: "ro",
-     fields: [
-      {bits: "0", name: "TX", desc: "TX buffer full" }
-      {bits: "1", name: "RX", desc: "RX buffer full"}
-      {bits: "2", name: "TXO", desc: "TX buffer overflow"}
-      {bits: "3", name: "RXO", desc: "RX buffer overflow"}
-      {bits: "4", name: "TXEMPTY", desc: "TX buffer empty"}
-      {bits: "5", name: "TXIDLE", desc: "TX idle"}
-      {bits: "6", name: "RXIDLE", desc: "RX idle"}
-      {bits: "7", name: "RXEMPTY", desc: "RX fifo empty"}
-    ]}
-    // I suspect STATECLR should be r0w1c or something
-    {name: "STATECLR", desc: "UART state register", swaccess: "rw",
-     fields: [
-      {bits: "19", name: "TXO", desc: "Clear TX buffer overflow"}
-      {bits: "20", name: "RXO", desc: "Clear RX buffer overflow"}
-    ]}
-    {name: "ISTATE", desc: "UART Interrupt state register", swaccess: "ro",
-     fields: [
-      {bits: "0", name: "TX", desc: "TX interrupt state" }
-      {bits: "1", name: "RX", desc: "RX interrupt state"}
-      {bits: "2", name: "TXO", desc: "TX overflow interrupt state"}
-      {bits: "3", name: "RXO", desc: "RX overflow interrupt state"}
-      {bits: "4", name: "RXF", desc: "RX frame error interrupt state"}
-      {bits: "5", name: "RXB", desc: "RX break error interrupt state"}
-      {bits: "6", name: "RXTO", desc: "RX timeout interrupt state"}
-      {bits: "7", name: "RXPE", desc: "RX parity error interrupt state"}
-    ]}
-    {name: "ISTATECLR", desc: "UART Interrupt clear register",
-     swaccess: "r0w1c",
-     fields: [
-      {bits: "0", name: "TX", desc: "Clear TX interrupt" }
-      {bits: "1", name: "RX", desc: "Clear RX interrupt"}
-      {bits: "2", name: "TXO", desc: "Clear TX overflow interrupt"}
-      {bits: "3", name: "RXO", desc: "Clear RX overflow interrupt"}
-      {bits: "4", name: "RXF", desc: "Clear RX frame error interrupt"}
-      {bits: "5", name: "RXB", desc: "Clear RX break error interrupt"}
-      {bits: "6", name: "RXTO", desc: "Clear RX timeout interrupt"}
-      {bits: "7", name: "RXPE", desc: "Clear RX parity error interrupt"}
-    ]}
-    {name: "FIFO", desc: "UART FIFO control register", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "RXRST", swaccess: "r0w1c", desc: "RX fifo reset" }
-      {bits: "1", name: "TXRST", swaccess: "r0w1c", desc: "TX fifo reset" }
-      {bits: "4:2", name: "RXILVL",
-       desc: "Trigger level for RX interrupts"
-       enum: [
-       	       { value: "0", name: "rxlvl1", desc: "1 character" },
-       	       { value: "1", name: "rxlvl4", desc: "4 characters" },
-       	       { value: "2", name: "rxlvl8", desc: "8 characters" },
-       	       { value: "3", name: "rxlvl16", desc: "16 characters" }
-       	       { value: "4", name: "rxlvl30", desc: "30 characters" }
-	       // TODO expect generator to make others reserved
-	     ]
-      }
-      {bits: "6:5", name: "TXILVL",
-       desc: "Trigger level for TX interrupts"
-       enum: [
-       	       { value: "0", name: "txlvl1", desc: "1 character" },
-       	       { value: "1", name: "txlvl4", desc: "4 characters" },
-       	       { value: "2", name: "txlvl8", desc: "8 characters" },
-       	       { value: "3", name: "txlvl16", desc: "16 characters" }
-	     ]
-      }
-    ]}
-    {name: "RFIFO", desc: "UART FIFO status register", swaccess: "ro",
-     fields: [
-      {bits: "5:0", name: "TXLVL", desc: "Current fill level of TX fifo" }
-      {bits: "11:6", name: "RXLVL", desc: "Current fill level of RX fifo" }
-    ]}
-    {name: "OVRD", desc: "UART override control register", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "TXEN", desc: "Override the TX signal" }
-      {bits: "1", name: "TXVAL", desc: "Value for TX Override" }
-      {bits: "2", name: "RTSEN", desc: "Override the RTS signal" }
-      {bits: "3", name: "RTSVAL", desc: "Value for RTS Override" }
-    ]}
-    {name: "VAL", desc: "UART oversampled values", swaccess: "ro",
-     fields: [
-      {bits: "15:0", name: "RX", desc: '''
-       Last 16 oversampled values of RX. Most recent bit is bit 0, oldest 15.
-      ''' }
-      {bits: "31:16", name: "CTS", desc: '''
-       Last 16 oversampled values of CTS. Most recent bit is bit 16, oldest 31.
-      ''' }
-    ]}
-    {name: "RXTO", desc: "UART RX timeout control", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "EN", desc: "Enable RX timeout feature" }
-      {bits: "24:1", name: "VAL", desc: "RX timeout value in UART bit times" }
-    ]}
-    { skipto: "0x0f00" }
-    {name: "ITCR", desc: "UART Integration test control", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "", desc: "-" }
-    ]}
-    {name: "ITOP", desc: "UART Integration test overrides", swaccess: "rw",
-     fields: [
-      {bits: "0", name: "TX", desc: "Drive txint when UART_ITCR asserted" }
-      {bits: "1", name: "RX", desc: "Drive rxint when UART_ITCR asserted" }
-      {bits: "2", name: "TXO", desc: "Drive txoint when UART_ITCR asserted" }
-      {bits: "3", name: "RXO", desc: "Drive rxoint when UART_ITCR asserted" }
-      {bits: "4", name: "RXF", desc: "Drive rxfint when UART_ITCR asserted" }
-      {bits: "5", name: "RXB", desc: "Drive rxbint when UART_ITCR asserted" }
-      {bits: "6", name: "RXTO", desc: "Drive rxtoint when UART_ITCR asserted" }
-      {bits: "7", name: "RXPE", desc: "Drive rxpeint when UART_ITCR asserted" }
-    ]}
-    {name: "DVREG", desc: "DV-accessible test register", swaccess: "rw",
-     fields: [
-      {bits: "7:0", name: "", desc: "-" }
-    ]}
-  ]
-}
diff --git a/util/docgen/generate.py b/util/docgen/generate.py
deleted file mode 100644
index 05f2de7..0000000
--- a/util/docgen/generate.py
+++ /dev/null
@@ -1,97 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-import logging
-import os
-import shutil
-import sys
-
-import mistletoe
-from pkg_resources import resource_filename
-
-from . import html_data, lowrisc_renderer
-
-
-def generate_doc(src_path, verbose, inlinecss, inlinewave, asdiv):
-    """Generate Document for other library to use
-    """
-
-    if src_path == '-':
-        infile = sys.stdin
-    else:
-        if os.path.isfile(src_path):
-            infile = open(src_path, 'r', encoding='UTF-8')
-        else:
-            logging.error("Source is not a file: %s", src_path)
-            return ""
-
-    if (asdiv):
-        outstr = html_data.header_asdiv
-        # no body to add the onload to, so must inline waveforms
-        inlinewave = True
-    elif (inlinewave):
-        outstr = html_data.header_waveinline
-    else:
-        outstr = html_data.header_wavejs
-
-    if (asdiv):
-        logging.info("asdiv: no CSS included")
-    elif (inlinecss):
-        outstr += "<style type='text/css'>"
-        with open(
-                resource_filename('docgen', 'md_html.css'), 'r',
-                encoding='UTF-8') as fin:
-            outstr += fin.read()
-        with open(
-                resource_filename('reggen', 'reg_html.css'), 'r',
-                encoding='UTF-8') as fin:
-            outstr += fin.read()
-        outstr += "</style>"
-    else:
-        outstr += '<link rel="stylesheet" type="text/css" href="md_html.css">'
-        outstr += '<link rel="stylesheet" type="text/css" href="reg_html.css">'
-
-    outstr += html_data.markdown_header
-
-    # lowrisc_renderer.Document rather than mistletoe.Document to get includes
-    with infile:
-        with lowrisc_renderer.LowriscRenderer(
-                srcfile=src_path, wavejs=not inlinewave) as renderer:
-            document = lowrisc_renderer.Document(infile, src_path)
-            rendered = renderer.render(document)
-            tocpos = rendered.find(html_data.toc_mark_head)
-            toc = renderer.toc
-            if tocpos < 0 or len(toc) == 0:
-                outstr += rendered
-            else:
-                tocp = tocpos + len(html_data.toc_mark_head)
-                toci = tocp
-                while rendered[tocp] != '-':
-                    tocp += 1
-                maxlvl = int(rendered[toci:tocp])
-                outstr += rendered[:tocpos]
-                outstr += html_data.toc_title
-                outstr += '<ul>\n'
-                lvl = 2
-                for x in toc:
-                    # don't expect H1, collapse to H2 if it is there
-                    wantlvl = x[0] if x[0] > 1 else 2
-                    if (wantlvl > maxlvl):
-                        continue
-                    while lvl < wantlvl:
-                        outstr += '<ul>\n'
-                        lvl += 1
-                    while lvl > wantlvl:
-                        outstr += '</ul>\n'
-                        lvl -= 1
-                    outstr += '<li><a href=#' + x[2] + '>' + x[1] + '</a>\n'
-                while lvl > 1:
-                    outstr += '</ul>\n'
-                    lvl -= 1
-                outstr += rendered[tocpos:]
-
-    outstr += html_data.markdown_trailer
-    outstr += html_data.trailer_asdiv if asdiv else html_data.trailer
-
-    return outstr
diff --git a/util/docgen/hjson_lexer.py b/util/docgen/hjson_lexer.py
deleted file mode 100644
index 23e64c1..0000000
--- a/util/docgen/hjson_lexer.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-     Hjson Lexer for pygments
-     ~~~~~~~~~~~~~~~~~~~~~~~~
-
-     Derived from JsonLexer in pygments.lexers.data
-     which is
-     :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS.
-     :license: BSD, see pygments LICENSE for details.
-
-     Modifications copyright lowRisc contributors
-"""
-
-import re
-
-from pygments.lexer import RegexLexer, include
-from pygments.token import (Comment, Error, Keyword, Literal, Name, Number,
-                            Punctuation, String, Text)
-
-
-class HjsonLexer(RegexLexer):
-    """
-     For HJSON data structures.
-
-     .. versionadded:: 1.5
-     """
-
-    name = 'HJSON'
-    aliases = ['hjson']
-    filenames = ['*.hjson']
-    mimetypes = ['application/hjson']
-
-    flags = re.DOTALL
-
-    # integer part of a number
-    int_part = r'-?(0|[1-9]\d*)'
-
-    # fractional part of a number
-    frac_part = r'\.\d+'
-
-    # exponential part of a number
-    exp_part = r'[eE](\+|-)?\d+'
-
-    tokens = {
-        'whitespace': [
-            (r'\s+', Text),
-        ],
-
-        # represents a simple terminal value
-        'simplevalue': [
-            (r'(true|false|null)\b', Keyword.Constant),
-            (('%(int_part)s(%(frac_part)s%(exp_part)s|'
-              '%(exp_part)s|%(frac_part)s)') % vars(), Number.Float),
-            (int_part, Number.Integer),
-            (r'"(\\\\|\\"|[^"])*"', String.Double),
-        ],
-
-        # the right hand side of an object, after the attribute name
-        'objectattribute': [
-            include('value'),
-            (r':', Punctuation),
-            # triple quote is a multiline string
-            # accept any non-quote, single quote plus non-quote
-            # two quotes plus non-quote to cover all cases
-            (r"'''([^']|'[^']|''[^'])*'''", Text),
-            # comma terminates the attribute but expects more
-            (r',', Punctuation, '#pop'),
-            # a closing bracket terminates the entire object, so pop twice
-            (r'\}', Punctuation, '#pop:2'),
-            # comma is optional in hjson so terminate on anything else
-            # but use re syntax so this match does not consume it
-            # This is should really only be done if a value or string matched
-            (r'(?=.)', Text, '#pop'),
-        ],
-
-        # a json object - { attr, attr, ... }
-        'objectvalue': [
-            include('whitespace'),
-            # a comment
-            (r'#[^\n]*', Comment.Single),
-            (r'//[^\n]*', Comment.Single),
-            (r'"(\\\\|\\"|[^"])*"|(\\\\|[^:])*', Name.Tag, 'objectattribute'),
-            (r'\}', Punctuation, '#pop'),
-        ],
-
-        # json array - [ value, value, ... }
-        'arrayvalue': [
-            include('whitespace'),
-            (r'#[^\n]*', Comment.Single),
-            (r'//[^\n]*', Comment.Single),
-            include('value'),
-            (r',', Punctuation),
-            (r'\]', Punctuation, '#pop'),
-        ],
-
-        # a json value - either a simple value or a complex value
-        # (object or array)
-        'value': [
-            include('whitespace'),
-            (r'#[^\n]*', Comment.Single),
-            (r'//[^\n]*', Comment.Single),
-            include('simplevalue'),
-            (r'\{', Punctuation, 'objectvalue'),
-            (r'\[', Punctuation, 'arrayvalue'),
-        ],
-
-        # the root of a json document whould be a value
-        'root': [
-            (r'#[^\n]*', Comment.Single),
-            (r'//[^\n]*', Comment.Single),
-            include('value'),
-            # hjson does not require the outer {}
-            # this is also helpful for styleguide examples!
-            include('objectvalue'),
-        ],
-    }
diff --git a/util/docgen/html_data.py b/util/docgen/html_data.py
deleted file mode 100644
index 87bcd0c..0000000
--- a/util/docgen/html_data.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-header_wavejs = """
-<html>
-<head>
-<meta charset="UTF-8">
-<script src="https://cdnjs.cloudflare.com/ajax/libs/wavedrom/2.1.2/skins/default.js"
-        type="text/javascript"></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/wavedrom/2.1.2/wavedrom.min.js"
-       type="text/javascript"></script>
-</head>
-<body onload="WaveDrom.ProcessAll()">
-"""
-
-header_waveinline = """
-<html>
-<head>
-<meta charset="UTF-8">
-</head>
-"""
-
-header_asdiv = """
-<div>
-"""
-
-markdown_header = """
-<div class="mdown">
-"""
-
-markdown_trailer = """
-</div>
-"""
-
-register_header = """
-<div>
-"""
-
-register_trailer = """
-</div>
-"""
-
-hwcfg_header = """
-<div class="mdown">
-"""
-
-hwcfg_trailer = """
-</div>
-"""
-
-trailer = """
-</body>
-</html>
-"""
-
-trailer_asdiv = """
-</div>
-"""
-
-lowrisc_title_head = """
-<table class="section_heading">
-<tr><td>lowRISC Comportable IP Document</td></tr>
-<tr><td>
-"""
-
-lowrisc_title_tail = """
-</td></tr>
-<tr><td>&copy; lowrisc.org Contributors</td></tr></table>
-"""
-
-section_template = """
-<table class="{cls}" id="{id}">
-<tr><td>{inner}</td></tr></table>
-"""
-
-doctree_head = "<ul>"
-doctree_template = """
-<li> <a href="{link}">{text}</a> </li>
-"""
-doctree_tail = "</ul>"
-
-toc_title = """
-<h2>Table of Contents</h2>
-"""
-
-toc_mark_head = "<!--TOC "
-toc_mark_tail = "-->\n"
-
-dashboard_header = """
-  <table class="hw-project-dashboard">
-    <thead>
-      <tr>
-        <th>Module</th>
-        <th>Version</th>
-        <th>Life Stage</th>
-        <th>Design Stage</th>
-        <th>Verification Stage</th>
-        <th>Notes</th>
-      </tr>
-    </thead>
-    <tbody>
-"""
-dashboard_trailer = """
-    </tbody>
-  </table>
-"""
-
-specboard_header = """
-  <table class="hw-project-dashboard">
-    <thead>
-      <tr>
-        <th>Module</th>
-        <th>Design Spec</th>
-        <th>DV Plan</th>
-      </tr>
-    </thead>
-    <tbody>
-"""
-specboard_trailer = """
-    </tbody>
-  </table>
-"""
diff --git a/util/docgen/lowrisc_renderer.py b/util/docgen/lowrisc_renderer.py
deleted file mode 100644
index 0375a80..0000000
--- a/util/docgen/lowrisc_renderer.py
+++ /dev/null
@@ -1,450 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-"""
-Provides lowRISC extension support for rendering Markdown to html.
-{{% }} directives
-!!Reg !!Reg.Field to generate cross reference to registers
-Syntax highlighting with pygments
-Conversion of WaveJSON timing diagrams
-Adapted from examples in mistletoe.contrib
-<https://github.com/miyuchina/mistletoe/blob/master/contrib/>
-"""
-
-import io
-import logging as log
-import os.path as path
-import re
-import subprocess
-import sys
-from itertools import chain
-from os import walk
-from pathlib import Path
-from urllib.parse import urlparse, urlunparse
-
-import hjson
-import mistletoe.block_token
-import mistletoe.span_token
-from mistletoe import HTMLRenderer
-from mistletoe.block_token import BlockToken, CodeFence, add_token, tokenize
-from mistletoe.span_token import EscapeSequence, RawText, SpanToken
-from pkg_resources import resource_filename
-from pygments import highlight
-from pygments.formatters.html import HtmlFormatter
-from pygments.lexers import get_lexer_by_name as get_lexer
-from pygments.lexers import guess_lexer
-from pygments.styles import get_style_by_name as get_style
-
-import dashboard.gen_dashboard_entry as gen_dashboard_entry
-import reggen.gen_cfg_html as gen_cfg_html
-import reggen.gen_html as gen_html
-import reggen.validate as validate
-from docgen import html_data, mathjax
-from docgen.hjson_lexer import HjsonLexer
-from testplanner import class_defs, testplan_utils
-from wavegen import wavesvg
-
-
-# mirrors Document but adds includes
-# have to pull all the sub-files in to the main text so cross-links work
-# By default anchor links only resolve within a single file
-# arguably this is correct isolation but we want to be able to include anchors
-class Document(BlockToken):
-    """
-    Document token with includes.
-    """
-
-    # Called when the include directive starts with a !
-    # to indicate execute the first word as a command with rest as opts
-    # To help avoid mistakes (and mimimally help avoid attacks in the case
-    # of a trusted docgen given untrusted input files) the command must
-    # live inside the repo (the example uses a local ls script to
-    # run a command from outside, but the script was reviewed and checkedin)
-    def exec_include(self, include_text, basedir):
-        expand = include_text.split(maxsplit=1)
-        cmd = expand[0]
-        opts = '' if len(expand) < 2 else expand[1]
-        abscmd = path.abspath(path.join(basedir, cmd))
-        if not abscmd.startswith(self.treetop):
-            log.error("Blocked include: " + cmd + ' (' + abscmd +
-                      ") is outside the repo.")
-            raise NameError('Command file must be in the repo')
-        # do the cd in the subprocess to avoid save/restore of cwd
-        res = subprocess.run(
-            'cd ' + basedir + '; ' + abscmd + ' ' + opts,
-            shell=True,
-            universal_newlines=True,
-            stdout=subprocess.PIPE).stdout
-        return res.splitlines(keepends=True)
-
-    def add_include(self, l, pat, basedir):
-        lines = []
-        for line in l:
-            match = pat.search(line)
-            # because this is pre-processed a sepcial case is needed to
-            # allow documentation with include command inside back-ticks
-            if (match and not (match.start() > 0 and
-                               line[match.start() - 1] == '`')):
-                lines.append(line[:match.start()] + line[match.end():])
-                if match.group(1)[0] == "!":
-                    try:
-                        res = self.exec_include(match.group(1)[1:], basedir)
-                        lines.extend(self.add_include(res, pat, basedir))
-                    except NameError:
-                        lines.append("Blocked execution of " + match.group(1))
-                else:
-                    incfname = path.join(basedir, match.group(1))
-                    try:
-                        incfile = open(incfname, 'r', encoding='UTF-8')
-                        with incfile:
-                            newdir = path.dirname(incfname)
-                            lines.extend(
-                                self.add_include(incfile, pat, newdir))
-                    except OSError as err:
-                        log.error("Could not open include file: " + str(err))
-                        lines.append("Failed to include " + incfname + "\n\n")
-            else:
-                lines.append(line)
-        return lines
-
-    def __init__(self, lines, srcfile):
-        docdir = path.dirname(resource_filename('docgen', 'md_html.css'))
-        self.treetop = path.abspath(path.join(docdir, "../.."))
-        pat = re.compile(r"\{\{\% *include +(.+?) *\}\}")
-        basedir = ""
-        if len(srcfile) > 0:
-            basedir = path.dirname(srcfile)
-        if basedir == '':
-            basedir = '.'
-        if isinstance(lines, str):
-            lines = lines.splitlines(keepends=True)
-
-        lines = self.add_include(lines, pat, basedir)
-        self.footnotes = {}
-        mistletoe.block_token._root_node = self
-        mistletoe.span_token._root_node = self
-        self.children = tokenize(lines)
-        mistletoe.span_token._root_node = None
-        mistletoe.block_token._root_node = None
-
-
-# mirrors the CodeFence in mistletoe but with additional parameter
-# note this maintains the bug with `~` matching the RE
-class CodeFenceDirective(CodeFence):
-    """
-    Code fence with language and directive
-
-    Supports code blocks starting
-    ```language {directive}
-    Up to 3 spaces indentation, minimum of 3 fence characters,
-    optional spaces, language text, optional spaces, open {,
-    optional spaces, directive text, optional spaces, close }
-    at the moment there cannot be spaces inside language or directive
-    """
-    # future may want something like \{ *([^\}]*\} for multiple directives
-    pattern = re.compile(r'( {0,3})((?:`|~){3,}) *(\S+) *\{ *(\S*) *\}')
-    _open_info = None
-
-    def __init__(self, match):
-        lines, open_info = match
-        self.language = EscapeSequence.strip(open_info[2])
-        self.directive = EscapeSequence.strip(open_info[3])
-        self.children = (RawText(''.join(lines)), )
-
-    @classmethod
-    def start(cls, line):
-        match_obj = cls.pattern.match(line)
-        if not match_obj:
-            return False
-        prepend, leader, lang, direct = match_obj.groups()
-        if (leader[0] in lang or leader[0] in direct or
-                leader[0] in line[match_obj.end():]):
-            return False
-        cls._open_info = len(prepend), leader, lang, direct
-        return True
-
-
-class LowriscEscape(SpanToken):
-    pattern = re.compile(r"\{\{\% *(.+?) +(.+?) *\}\}")
-
-    def __init__(self, match):
-        self.type = match.group(1)
-        self.text = match.group(2)
-
-
-class RegRef(SpanToken):
-    pattern = re.compile(r"!!([A-Za-z0-9_.]+)")
-
-    def __init__(self, match):
-        self.rname = match.group(1)
-
-
-class LowriscRenderer(mathjax.MathJaxRenderer):
-    formatter = HtmlFormatter()
-    formatter.noclasses = True
-
-    def __init__(self, *extras, style='default', srcfile='', wavejs=False):
-        # yapf requests different formatting for this code block depending on
-        # the Python3 version. Work around that by disabling yapf for this code
-        # block.
-        # Bug: https://github.com/google/yapf/issues/696
-        # yapf: disable
-        super().__init__(*chain((LowriscEscape, RegRef,
-                                 CodeFenceDirective), extras))
-        # yapf: enable
-        self.formatter.style = get_style(style)
-        self.regs = None
-        self.wavejs = wavejs
-        self.num_svg = 0
-        # compute base of srcfile to allow relative imports
-        basedir = ""
-        if len(srcfile) > 0:
-            basedir = path.dirname(srcfile)
-        self.basedir = basedir
-        self.toc = []
-
-    # Convert the inner text of header or section into id for html href
-    # inner is a flat string but may have html tags
-    # html id rules are:
-    #    Must contain at least one character
-    #    Must not contain any space characters
-    # Want to match github, can't find its exact rules
-    # The id is derived from the heading text by stripping html tags,
-    # changing whitespace to - and lower-casing.
-    # e.g. 'Theory of operation' becomes 'theory-of-operation
-    # TODO worry about & eg 'Foo & Bar' becomes 'foo-&-bar'
-    def id_from_inner(self, inner):
-        return re.sub(r'\s+', '-', re.sub(r'<.+?>', '', inner)).lower()
-
-    def render_lowrisc_code(self, token, directive):
-        code = token.children[0].content
-        # parser seems to get confused (eg by `~`) and makes empty calls
-        if len(code) == 0:
-            log.warn('Unexpected empty code block. Check for `~`')
-            return ""
-        # waveforms look like embedded code in the markdown
-        # but the WaveDrom javascript wants it in a script tag
-        if token.language == "wavejson":
-            if self.wavejs:
-                return '<script type="WaveDrom">' + code + '</script>'
-            else:
-                try:
-                    wvobj = hjson.loads(code, use_decimal=True)
-                except ValueError as err:
-                    log.warn('wavejson parse failed at line ' +
-                             str(err.lineno) + ': ' + err.msg)
-                    return '<pre>Error line '  + str(err.lineno) + \
-                        ': ' + err.msg + " in:\n" + code[:err.pos] + \
-                        '</pre><pre style="color:red">' + \
-                        code[err.pos:] + '</pre>'
-                self.num_svg += 1
-                return wavesvg.convert(wvobj, self.num_svg - 1)
-        else:
-            # pygments.util.ClassNotFound subclass of ValueError
-            lexer = None
-            if (token.language):
-                if token.language == 'hjson':
-                    lexer = HjsonLexer()
-                else:
-                    try:
-                        lexer = get_lexer(token.language)
-                    except ValueError:
-                        log.info('Failed to get lexer for language=' +
-                                 token.language)
-                        lexer = None
-            if lexer == None:
-                try:
-                    lexer = guess_lexer(code)
-                    log.info('Guess lexer as ' + lexer.name)
-                except ValueError:
-                    log.info('Failed to guess lexer for code=' + code)
-                    lexer = None
-            if lexer:
-                if directive == '.good':
-                    self.formatter.cssstyles='background:#e0ffe0; ' \
-                        'border-left-color: #108040;'
-                elif directive == '.bad':
-                    self.formatter.cssstyles='background:#ffe0e0; ' \
-                        'border-left-color: #c04030'
-                else:
-                    self.formatter.cssstyles = ''
-
-                return highlight(code, lexer, self.formatter)
-            else:
-                return super().render_block_code(token)
-
-    def render_code_fence_directive(self, token):
-        return self.render_lowrisc_code(token, token.directive)
-
-    def render_block_code(self, token):
-        return self.render_lowrisc_code(token, '')
-
-    def render_lowrisc_escape(self, token):
-        # plan eventually to allow lowrisc-doc-hdr=doctype
-        if token.type[:15] == "lowrisc-doc-hdr":
-            return html_data.lowrisc_title_head + token.text + \
-                   html_data.lowrisc_title_tail
-        if token.type == "toc":
-            return html_data.toc_mark_head + token.text + \
-                   html_data.toc_mark_tail
-        if token.type == "regfile":
-            regfile = open(
-                path.join(self.basedir, token.text), 'r', encoding='UTF-8')
-            with regfile:
-                try:
-                    obj = hjson.load(
-                        regfile,
-                        use_decimal=True,
-                        object_pairs_hook=validate.checking_dict)
-                except ValueError:
-                    raise SystemExit(sys.exc_info()[1])
-            if validate.validate(obj) == 0:
-                log.info("Generated register object\n")
-                self.regs = obj
-            else:
-                log.warn("Register import failed\n")
-                self.regs = None
-            return ""
-        if token.type == "registers":
-            if self.regs == None:
-                return "<B>Errors parsing registers prevents insertion.</B>"
-            outbuf = io.StringIO()
-            # note for CSS need to escape the mdown class on the div
-            outbuf.write("</div>" + html_data.register_header)
-            gen_html.gen_html(self.regs, outbuf, toclist=self.toc, toclevel=3)
-            outbuf.write(html_data.register_trailer + '<div class="mdown">')
-            generated = outbuf.getvalue()
-            outbuf.close()
-            return generated
-        if token.type == "cfgfile":
-            log.error("Deprecated lowRISC token cfgfile ignored. Config is now"\
-                      " in a single file with the registers!")
-            return ""
-        if token.type == "hwcfg":
-            if self.regs == None:
-                return "<B>Errors parsing configuration prevents insertion.</B>"
-            outbuf = io.StringIO()
-            # note for CSS need to escape the mdown class on the div
-            outbuf.write("</div>" + html_data.hwcfg_header)
-            gen_cfg_html.gen_cfg_html(self.regs, outbuf)
-            outbuf.write(html_data.hwcfg_trailer + '<div class="mdown">')
-            generated = outbuf.getvalue()
-            outbuf.close()
-            return generated
-        if token.type == "section1":
-            # TODO should token.text get parsed to allow markdown in it?
-            id = self.id_from_inner(token.text)
-            self.toc.append((2, token.text, id))
-            return html_data.section_template.format(
-                cls="section_heading", id=id, inner=token.text)
-        if token.type == "section2":
-            # TODO should token.text get parsed to allow markdown in it?
-            id = self.id_from_inner(token.text)
-            self.toc.append((3, token.text, id))
-            return html_data.section_template.format(
-                cls="subsection_heading", id=id, inner=token.text)
-        if token.type == "doctree":
-            md_paths = []
-            return_string = ''
-            subdirs = [path.join(self.basedir, s) for s in token.text.split()]
-            for subdir in sorted(subdirs):
-                md_paths.extend(sorted(Path(subdir).rglob('*.md')))
-            for md_path in md_paths:
-                rel_md_path = md_path.relative_to(self.basedir)
-                return_string += html_data.doctree_template.format(
-                    link=rel_md_path.with_suffix('.html'),
-                    text=rel_md_path.with_suffix(''))
-            return html_data.doctree_head + return_string + html_data.doctree_tail
-        if token.type == "import_testplan":
-            self.testplan = testplan_utils.parse_testplan(
-                path.join(self.basedir, token.text))
-            return ""
-        if token.type == "insert_testplan":
-            if self.testplan == None:
-                return "<B>Errors parsing testplan prevents insertion.</B>"
-            outbuf = io.StringIO()
-            testplan_utils.gen_html_testplan_table(self.testplan, outbuf)
-            generated = outbuf.getvalue()
-            outbuf.close()
-            return generated
-        if token.type == "dashboard":
-            hjson_paths = []
-            # find all of the .prj.hjson files in the given path
-            hjson_paths.extend(
-                sorted(
-                    Path(path.join(self.basedir,
-                                   token.text)).rglob('*.prj.hjson')))
-            outbuf = io.StringIO()
-            outbuf.write(html_data.dashboard_header)
-            for hjson_path in hjson_paths:
-                gen_dashboard_entry.gen_dashboard_html(hjson_path, outbuf)
-            outbuf.write(html_data.dashboard_trailer)
-            generated = outbuf.getvalue()
-            outbuf.close()
-            return generated
-        if token.type == "specboard":
-            hjson_paths = []
-            # find all of the .prj.hjson files in the given path
-            hjson_paths.extend(
-                sorted(
-                    Path(path.join(self.basedir,
-                                   token.text)).rglob('*.prj.hjson')))
-            outbuf = io.StringIO()
-            outbuf.write(html_data.specboard_header)
-            for hjson_path in hjson_paths:
-                gen_dashboard_entry.gen_specboard_html(hjson_path,
-                    hjson_path.relative_to(self.basedir), outbuf)
-            outbuf.write(html_data.specboard_trailer)
-            generated = outbuf.getvalue()
-            outbuf.close()
-            return generated
-
-        bad_tag = '{{% ' + token.type + ' ' + token.text + ' }}'
-        log.warn("Unknown lowRISC tag " + bad_tag)
-        return bad_tag
-
-    def render_reg_ref(self, token):
-        if self.regs == None:
-            log.warn("!!" + token.rname + ": no register import was done.")
-            return '!!' + token.rname
-        cname = self.regs['name']
-        base = token.rname.partition('.')[0].lower()
-        if not base in self.regs['genrnames']:
-            log.warn("!!" + token.rname + " not found in register list.")
-            return '!!' + token.rname
-
-        if token.rname[-1] == ".":
-            return '<a href="#Reg_' + base + '"><code class=\"reg\">' + \
-                cname + "." + token.rname[:-1] + '</code></a>.'
-        else:
-            return '<a href="#Reg_' + base + '"><code class=\"reg\">' + \
-                cname + "." + token.rname + '</code></a>'
-
-    # copied from mistletoe/html_renderer.py and id added
-    # override heading to insert reference for anchor
-    def render_heading(self, token):
-        template = '<h{level} id="{id}">{inner}</h{level}>'
-        inner = self.render_inner(token)
-        id = self.id_from_inner(inner)
-        self.toc.append((token.level, inner, id))
-        return template.format(level=token.level, inner=inner, id=id)
-
-    # decorator for link rendering functions in class HTMLRenderer
-    # converts relative .md link targets to .html link targets
-    def _convert_local_links(func):
-        def _wrapper_convert_local_links(*args, **kwargs):
-            target_url = urlparse(args[1].target)
-            target_path = Path(target_url.path)
-            # check link is not absolute
-            if not target_url.netloc and target_path.suffix in ['.md', '.mkd']:
-                target_url = target_url._replace(
-                    path=str(target_path.with_suffix('.html')))
-                args[1].target = urlunparse(target_url)
-
-            return func(*args, **kwargs)
-
-        return _wrapper_convert_local_links
-
-    # apply to the link rendering functions inherited from HTMLRenderer
-    render_link = _convert_local_links(HTMLRenderer.render_link)
-    render_auto_link = _convert_local_links(HTMLRenderer.render_auto_link)
diff --git a/util/docgen/mathjax.py b/util/docgen/mathjax.py
deleted file mode 100644
index ca3eb8e..0000000
--- a/util/docgen/mathjax.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copied from mistletoe.contrib
-# <https://github.com/miyuchina/mistletoe/blob/master/contrib/mathjax.py>
-#
-# mistletoe is licenced under the MIT license see LICENSE.mistletoe
-#
-"""
-Provides MathJax support for rendering Markdown with LaTeX to html.
-Taken from mistletoe.contrib <https://github.com/miyuchina/mistletoe/blob/master/contrib/mathjax.py>
-"""
-
-from mistletoe.html_renderer import HTMLRenderer
-from mistletoe.latex_renderer import LaTeXRenderer
-
-
-class MathJaxRenderer(HTMLRenderer, LaTeXRenderer):
-    """
-    MRO will first look for render functions under HTMLRenderer,
-    then LaTeXRenderer.
-    """
-    mathjax_src = '<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML"></script>\n'
-
-    def render_math(self, token):
-        """
-        Ensure Math tokens are all enclosed in two dollar signs.
-        """
-        if token.content.startswith('$$'):
-            return self.render_raw_text(token)
-        return '${}$'.format(self.render_raw_text(token))
-
-    def render_document(self, token):
-        """
-        Append CDN link for MathJax to the end of <body>.
-        """
-        return super().render_document(token) + self.mathjax_src
diff --git a/util/docgen/md_html.css b/util/docgen/md_html.css
deleted file mode 100644
index 429e442..0000000
--- a/util/docgen/md_html.css
+++ /dev/null
@@ -1,144 +0,0 @@
-/* Stylesheet for mistletoe output in class=mdown div */
-/* Copyright lowRISC contributors. */
-/* Licensed under the Apache License, Version 2.0, see LICENSE for details.*/
-/* SPDX-License-Identifier: Apache-2.0 */
-
-.mdown {
-  -ms-text-size-adjust: 100%;
-  -webkit-text-size-adjust: 100%;
-  color: #24292e;
-  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
-  font-size: 16px;
-  word-wrap: break-word;
-  width: 80%;
-  margin-left:auto;
-  margin-right:auto;
-}
-
-.mdown code,
-.mdown pre {
-  font-family: monospace, monospace;
-  font-size: 1em;
-  display: inline;
-  max-width: auto;
-  padding: 0;
-  margin: 0;
-  overflow: visible;
-  line-height: inherit;
-  word-wrap: normal;
-  background-color: transparent;
-  border: 0;
-}
-
-.mdown table {
-  border-spacing: 0;
-  border-collapse: collapse;
-  display: block;
-  width: 100%;
-  overflow: auto;
-}
-
-.mdown table th {
-  font-weight: 600;
-}
-
-.mdown table th,
-.mdown table td {
-  padding: 6px 13px;
-  border: 1px solid black;
-}
-
-.mdown table tr {
-  background-color: #fff;
-  border-top: 1px solid #c6cbd1;
-}
-
-.mdown table tr:nth-child(even) {
-  background-color: lightgray;
-}
-
-p.titleright {
-  font-size: 1em;
-  text-align: right;
-  font-weight: 600;
-}
-
-h1 {
-    text-align: center;
-}
-p.copy {
-    font-weight: 100;
-    font-size: 1em;
-    text-align: left;
-}
-
-code.reg {
-    font-family: monospace, monospace;
-    font-size: 0.8em;
-    color: blue;
-}
-
-.highlight {
-    border-left: 2px solid;
-    font-size: 80%;
-    padding: 12px 8px;
-}
-
-table.section_heading {
-    border: 2px solid black;
-    width: 100%;
-    font-size: 140%;
-    background-color:#ffe8e8;
-    text-align:center;
-    vertical-align:middle;
-    font-family: serif;
-    display: table;
-}
-
-table.section_heading tr,
-table.section_heading td {
-    border: 1px solid black;
-    width: 100%;
-    background-color:#ffe8e8;
-    border: 0px;
-    float: center;
-}
-
-table.subsection_heading {
-    border: 2px solid black;
-    width: 100%;
-    font-size: 110%;
-    background-color:white;
-    text-align:center;
-    vertical-align:middle;
-    font-family: serif;
-    display: table;
-}
-
-table.subsection_heading tr,
-table.subsection_heading td {
-    border: 1px solid black;
-    width: 100%;
-    background-color:white;
-    border: 0px;
-    float: center;
-}
-
-table.hw-project-dashboard table,
-table.hw-project-dashboard td,
-table.hw-project-dashboard th {
-    border: 1px solid #000080;
-}
-table.hw-project-dashboard table {
-    font-family: sans-serif;
-}
-table.hw-project-dashboard .fixleft {
-    font-family: monospace;
-    text-align: left;
-}
-table.hw-project-dashboard th {
-    background-color: #e0e0ff;
-}
-table.hw-project-dashboard td, tr, th {
-    padding: 4px;
-}
diff --git a/util/index.md b/util/index.md
deleted file mode 100644
index 96eb99b..0000000
--- a/util/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Tools
-
-These are predominantly Readme's with details about the tooling scripts. Make sure to also check the corresponding [Reference Manuals](../doc/rm/index.md).
-
-{{% doctree ./ }}
diff --git a/util/reggen/gen_cfg_html.py b/util/reggen/gen_cfg_html.py
index 3cf0308..7d07102 100644
--- a/util/reggen/gen_cfg_html.py
+++ b/util/reggen/gen_cfg_html.py
@@ -25,7 +25,7 @@
     genout(outfile, "<p>Referring to the \n")
     genout(
         outfile,
-        "<a href=\"https://github.com/lowRISC/opentitan/blob/master/doc/rm/comportability_specification.md\">\n"
+        "<a href=\"https://docs.opentitan.org/doc/rm/comportability_specification\">\n"
     )
     genout(outfile, "Comportable guideline for peripheral device functionality</a>,\n")
     genout(outfile,
diff --git a/util/testplanner/README.md b/util/testplanner/README.md
index 6376675..e4b664f 100644
--- a/util/testplanner/README.md
+++ b/util/testplanner/README.md
@@ -1,4 +1,5 @@
-{{% toc 4 }}
+---
+---
 
 # Testplanner tool
 
@@ -38,13 +39,13 @@
   that the reader gets the full picture of what and how the said feature is being
   tested.
 
-  Full [markdown](../doc/rm/markdown_usage_style.md) syntax is supported when writing
+  Full [markdown]({{< relref "doc/rm/markdown_usage_style" >}}) syntax is supported when writing
   the description.
 
 * **tests: list of actual written tests that maps to this planned test**
 
   Testplan is written very early in the V0 stage of the HW development
-  [life-cycle](../../doc/ug/hw_stages.md). When the DV engineer gets to actually
+  [life-cycle]({{< relref "doc/ug/hw_stages" >}}). When the DV engineer gets to actually
   developing the test, it may not map 1:1 to the planned test - it may be possible
   that an already written test that mapped to another planned test also satisfies
   the current one; OR it may also be possible that the planned test needs to be
@@ -160,10 +161,10 @@
 - **common_testplan.hjson**: shared testplan imported within the DUT tesplan
 - **foo_dv_plan.md**: DUT testplan imported within the DV plan doc in markdown
 
-In addition, see [UART DV Plan](../../hw/ip/uart/doc/uart_dv_plan.md) for a
+In addition, see [UART DV Plan]({{< relref "hw/ip/uart/doc/dv_plan" >}}) for a
 real 'production' example of inline expansion of an imported testplan as a table
-within the DV Plan document done using [docgen](../docgen/README.md).
-The [UART tesplan](../../hw/ip/uart/data/uart_testplan.hjson) imports the shared
+within the DV Plan document.
+The [UART tesplan](https://github.com/lowRISC/opentitan/blob/master/hw/ip/uart/data/uart_testplan.hjson) imports the shared
 testplans located at `hw/dv/tools/testplans` area.
 
 ### Limitations
@@ -185,11 +186,6 @@
 $ util/testplanner.py testplanner/examples/foo_testplan.hjson -o /tmp/foo_testplan_table.html
 ```
 
-Generate the testplan table in HTML styled with [docgen](../docgen/README.md):
-```console
-$ util/testplanner.py testplanner/examples/foo_testplan.hjson | ./docgen.py -c -o /tmp/foo_testplan_table.html
-```
-
 Generate regression results table in HTML to stdout:
 ```console
 $ util/testplanner.py testplanner/examples/foo_testplan.hjson -r testplanner/examples/foo_regr_results.hjson
@@ -201,14 +197,8 @@
     -r testplanner/examples/foo_regr_results.hjson -o /tmp/foo_regr_results.html
 ```
 
-Generate regression results table in HTML styled with [docgen](../docgen/README.md):
-```console
-$ util/testplanner.py testplanner/examples/foo_testplan.hjson \
-    -r testplanner/examples/foo_regr_results.hjson | ./docgen.py -c -o /tmp/foo_regr_results.html
-```
-
 ### APIs for external tools
-The [docgen](../docgen/README.md) invokes the testplanner utility functions
+The `util/build_docs.py` invokes the testplanner utility functions
 directly to parse the Hjson testplan and insert a HTML table within the DV
 plan document. This is done by invoking:
 ```console
diff --git a/util/testplanner/examples/foo_dv_plan.md b/util/testplanner/examples/foo_dv_plan.md
deleted file mode 100644
index 2524a0f..0000000
--- a/util/testplanner/examples/foo_dv_plan.md
+++ /dev/null
@@ -1,5 +0,0 @@
-{{% lowrisc-doc-hdr FOO DV plan }}
-{{% import_testplan foo_testplan.hjson }}
-
-## Testplan
-{{% insert_testplan x }}
diff --git a/util/uvmdvgen/README.md b/util/uvmdvgen/README.md
index 1df9efa..12c9c5e 100644
--- a/util/uvmdvgen/README.md
+++ b/util/uvmdvgen/README.md
@@ -72,7 +72,7 @@
 
 The boilerplate code for a UVM agent for an interface can be generated using the
 `-a` switch. This results in the generation of complete agent with classes that
-extend from the [DV library](../../hw/dv/sv/dv_lib/README.md). Please see
+extend from the [DV library]({{< relref "hw/dv/sv/dv_lib/README.md" >}}). Please see
 description for more details.
 
 The tool generates an interface, item, cfg, cov, monitor, driver and sequence
@@ -154,8 +154,8 @@
 
 The boilerplate code for a UVM environment and the testbench for a DUT can be
 generated using the `-e` switch. This results in the generation of classes that
-extend from [DV library](../../hw/dv/sv/dv_lib/README.md). If the `-c` switch is
-passed, it extends from [cip library](../../hw/dv/sv/cip_lib/README.md). With
+extend from [DV library]({{< relref "hw/dv/sv/dv_lib/README.md" >}}). If the `-c` switch is
+passed, it extends from [cip library]({{< relref "hw/dv/sv/cip_lib/doc" >}}). With
 `-ea` switch, user can provide a list of downstream agents to create within the
 environment. Please see description for more details.
 
@@ -190,7 +190,7 @@
 
   This is the UVM reg based RAL model. This is created for completeness. The
   actual RAL model needs to be generated prior to running simulations using the
-  [regtool](../reggen/README.md).
+  [regtool]({{< relref "util/reggen/README.md" >}}).
 
 * **env/i2c_host_scoreboard**
 
@@ -286,14 +286,14 @@
 * **Makefile**
 
   This is the simulation Makefile that is used as the starting point for
-  building and running tests using the [make flow](../../hw/dv/tools/README.md).
+  building and running tests using the [make flow]({{< relref "hw/dv/tools/README.md" >}}).
   It already includes the sanity and CSR suite of tests to allow users to start
   running tests right away.
 
 * **plan.md**
 
   This is the empty DV plan document that will describe the entire testbench. A
-  template for this is available [here](../../hw/dv/doc/dv_plan_template.md).
+  template for this is available [here](https://github.com/lowRISC/opentitan/blob/master/hw/dv/doc/dv_plan_template.md).
 
 #### Examples