| #!/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 | 
 | """mdbook preprocessor that generates ISA tables for the OTBN. | 
 |  | 
 | The preprocessor also handles `{{#otbn-insn-ref ... }}` links to the ISA Table. | 
 | """ | 
 |  | 
 | import json | 
 | import sys | 
 | import re | 
 | from pathlib import Path | 
 | import tempfile | 
 | import subprocess | 
 |  | 
 | from mdbook import utils as md_utils | 
 |  | 
 | REPO_TOP = Path(__file__).resolve().parents[1] | 
 |  | 
 | # We are looking to match on the following example strings | 
 | # {{#otbn-isa base }} | 
 | OTBN_ISA_BASE_PATTERN = re.compile(r'\{\{#otbn-isa\s+base\s*\}\}') | 
 | OTBN_ISA_BIGNUM_PATTERN = re.compile(r'\{\{#otbn-isa\s+bignum\s*\}\}') | 
 |  | 
 | # {{#otbn-insn-ref insn }} | 
 | OTBN_INSNREF_PATTERN = re.compile(r'\{\{#otbn-insn-ref\s+?(.+?)\s*?\}\}') | 
 |  | 
 | OTBN_SCRIPT = REPO_TOP / 'hw/ip/otbn/util/yaml_to_doc.py' | 
 | OTBN_CFG = REPO_TOP / 'hw/ip/otbn/data/insns.yml' | 
 | OTBN_IMPL = REPO_TOP / 'hw/ip/otbn/dv/otbnsim/sim/insn.py' | 
 |  | 
 |  | 
 | def main() -> None: | 
 |     md_utils.supports_html_only() | 
 |  | 
 |     (base_content, bignum_content) = get_listings() | 
 |  | 
 |     # load both the context and the book from stdin | 
 |     context, book = json.load(sys.stdin) | 
 |  | 
 |     isa_book_path = None | 
 |     for chapter in md_utils.chapters(book["sections"]): | 
 |         if chapter["source_path"] is None: | 
 |             continue | 
 |  | 
 |         if OTBN_ISA_BASE_PATTERN.search(chapter["content"]) \ | 
 |                 and OTBN_ISA_BIGNUM_PATTERN.search(chapter["content"]): | 
 |  | 
 |             chapter["content"] = OTBN_ISA_BASE_PATTERN.sub(base_content, chapter["content"]) | 
 |             chapter["content"] = OTBN_ISA_BIGNUM_PATTERN.sub(bignum_content, chapter["content"]) | 
 |  | 
 |             isa_book_path = chapter["source_path"] | 
 |             break | 
 |  | 
 |     if isa_book_path is None: | 
 |         sys.exit("No file was found with both {{#otbn-isa base}} and {{#otbn-isa bignum}}") | 
 |  | 
 |     def ref_to_link(m: re.Match): | 
 |         instr = m.group(1) | 
 |         ref = instr.replace(".", "").lower() | 
 |         return '<a href="/{}#{}"><code>{}</code></a>)'.format(isa_book_path, ref, instr) | 
 |  | 
 |     for chapter in md_utils.chapters(book["sections"]): | 
 |         chapter["content"] = \ | 
 |             OTBN_INSNREF_PATTERN.sub( | 
 |                 ref_to_link, | 
 |                 chapter["content"], | 
 |         ) | 
 |  | 
 |     # dump the book into stdout | 
 |     print(json.dumps(book)) | 
 |  | 
 |  | 
 | def get_listings() -> (str, str): | 
 |     """Use the otbn utility scripts to generate the ISA listings.""" | 
 |     with tempfile.TemporaryDirectory() as tmpdir: | 
 |         subprocess.run( | 
 |             [str(OTBN_SCRIPT), str(OTBN_CFG), str(OTBN_IMPL), tmpdir], | 
 |             check=True, | 
 |         ) | 
 |         tmpdir = Path(tmpdir) | 
 |         with open(tmpdir / "base.md") as f: | 
 |             base_content = f.read() | 
 |  | 
 |         with open(tmpdir / "bignum.md") as f: | 
 |             bignum_content = f.read() | 
 |  | 
 |     return (base_content, bignum_content) | 
 |  | 
 |  | 
 | if __name__ == "__main__": | 
 |     main() |