cva6/docs/scripts/spec_builder.py
slgth ab2283c075
Some checks failed
bender-up-to-date / bender-up-to-date (push) Has been cancelled
ci / build-riscv-tests (push) Has been cancelled
ci / execute-riscv64-tests (push) Has been cancelled
ci / execute-riscv32-tests (push) Has been cancelled
doc: keep documentation in sync with the code (#2558)
Both the ISA and design documentations use some parameters generated from the RTL (ports, parameters).
As of now, they are committed to the repository and can be out of sync with the code.

This PR removes them from the repository and freshly generates them from the code when building HTML files.

This PR also removes prebuilt HTML files (design & ISA docs) and generates them when building the top-level Read the Docs documentation (make -C docs).
2024-10-25 12:27:09 +02:00

295 lines
11 KiB
Python
Executable file

# Copyright 2024 Thales DIS France SAS
#
# Licensed under the Solderpad Hardware License, Version 2.1 (the "License");
# you may not use this file except in compliance with the License.
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
# You may obtain a copy of the License at https://solderpad.org/licenses/
#
# Original Author: Jean-Roch COULON - Thales
#!/usr/bin/python3
import re
import sys
import os
from classes import Parameter
from classes import PortIO
from define_blacklist import define_blacklist
from parameters_extractor import parameters_extractor
from parameters_extractor import writeout_parameter_table
from parameters_extractor import writeout_parameter_table_adoc
HEADER_RST = """\
..
Copyright 2024 Thales DIS France SAS
Licensed under the Solderpad Hardware License, Version 2.1 (the "License");
you may not use this file except in compliance with the License.
SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
You may obtain a copy of the License at https://solderpad.org/licenses/
Original Author: Jean-Roch COULON - Thales
"""
HEADER_ADOC = """\
////
Copyright 2024 Thales DIS France SAS
Licensed under the Solderpad Hardware License, Version 2.1 (the "License");
you may not use this file except in compliance with the License.
SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
You may obtain a copy of the License at https://solderpad.org/licenses/
Original Author: Jean-Roch COULON - Thales
////
"""
DEFAULT_PARAMS = {
'RVE': False,
'RVQ': False,
'RVZabha': False,
'RVZacas': False,
'RVZawrs': False,
'RVZfa': False,
'RVZfbf-RZvfbf': False,
'RVZfh': False,
'RVZfinx': False,
'RVZicbo': False,
'RVZicfilp': False,
'RVZpm': False,
'RVZsmepmp': False,
'RVZsmmpm': False,
'RVZsmrnmi': False,
'RVZsmstateen': False,
'RVZsscofpmf': False,
'RVZssdbltrp': False,
'RVZsstc': False,
'RVZtso': False,
'RVZvk': False,
'SV': 'SV0'
}
def print_to_rst(pathout, target, module, ports, comments):
fileout = f"{pathout}/port_{module}.rst"
print("Output file " + fileout)
with open(fileout, "w", encoding="utf-8") as fout:
fout.write(HEADER_RST)
fout.write(f".. _CVA6_{module}_ports:\n\n")
fout.write(f".. list-table:: **{module} module** IO ports\n")
fout.write(" :header-rows: 1\n")
fout.write("\n")
fout.write(" * - Signal\n")
fout.write(" - IO\n")
fout.write(" - Description\n")
fout.write(" - connexion\n")
fout.write(" - Type\n")
for i, port in enumerate(ports):
fout.write("\n")
fout.write(f" * - ``{port.name}``\n")
fout.write(f" - {port.direction}\n")
fout.write(f" - {port.description}\n")
fout.write(f" - {port.connexion}\n")
fout.write(f" - {port.data_type}\n")
fout.write("\n")
if len(comments) != 0:
fout.write(
f"Due to {target} configuration, some ports are tied to a static value. These ports do not appear in the above table, they are listed below\n"
)
fout.write("\n")
for comment in comments:
fout.write(f"| {comment[0]},\n| {comment[1]}\n")
fout.write("\n")
def print_to_adoc(pathout, target, module, ports, comments):
fileout = f"{pathout}/port_{module}.adoc"
print("Output file " + fileout)
# format comments
for comment in comments:
for i in range(len(comment)):
comment[i] = comment[i].replace('``', '`')
comment[i] = comment[i].replace('|', '*')
with open(fileout, "w", encoding="utf-8") as fout:
fout.write(HEADER_ADOC)
fout.write(f"[[_CVA6_{module}_ports]]\n\n")
fout.write(f".*{module} module* IO ports\n")
fout.write("|===\n")
fout.write("|Signal | IO | Description | connexion | Type\n\n")
for port in ports:
fout.write(f"|`{port.name}` | {port.direction} | {port.description} | {port.connexion} | {port.data_type}\n\n")
fout.write("|===\n")
if len(comments) != 0:
fout.write(
f"Due to {target} configuration, some ports are tied to a static value. These ports do not appear in the above table, they are listed below\n\n"
)
for comment in comments:
fout.write(f"{comment[0]},::\n* {comment[1]}\n")
fout.write("\n")
def _format_parameter_adoc(name, value):
if type(value) is bool:
ret = str(value).lower()
else:
ret = str(value)
return f":{name}: {ret}\n"
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--target", required=True)
parser.add_argument("--gen-config", help="Generate target variables documentation file")
parser.add_argument("--gen-parameters", help="Generate target parameters files")
parser.add_argument("--gen-ports-folder", help="Generate target ports files")
args = parser.parse_args()
target = args.target
parameters = parameters_extractor(target)
# User_cfg
export_user_cfg_doc("01_cva6_user/user_cfg_doc.rst", parameters)
# Parameters
if args.gen_parameters is not None:
os.makedirs(os.path.dirname(args.gen_parameters), exist_ok=True)
writeout_parameter_table_adoc(args.gen_parameters, parameters, target)
print(f"File {args.gen_parameters} written")
# Config
if args.gen_config is not None:
os.makedirs(os.path.dirname(args.gen_config), exist_ok=True)
with open(args.gen_config, "w") as fout:
fout.write(f":ohg-config: {target.upper()}\n")
for name, value in DEFAULT_PARAMS.items():
fout.write(_format_parameter_adoc(name, value))
for name, parameter in parameters.items():
fout.write(_format_parameter_adoc(name, parameter.value))
print(f"File {args.gen_config} written")
# Ports
if args.gen_ports_folder is not None:
file = []
file.append("../core/cva6.sv")
file.append("../core/frontend/frontend.sv")
file.append("../core/frontend/bht.sv")
file.append("../core/frontend/btb.sv")
file.append("../core/frontend/ras.sv")
file.append("../core/frontend/instr_queue.sv")
file.append("../core/frontend/instr_scan.sv")
file.append("../core/instr_realign.sv")
file.append("../core/id_stage.sv")
file.append("../core/issue_stage.sv")
file.append("../core/ex_stage.sv")
file.append("../core/commit_stage.sv")
file.append("../core/controller.sv")
file.append("../core/csr_regfile.sv")
file.append("../core/decoder.sv")
file.append("../core/compressed_decoder.sv")
file.append("../core/scoreboard.sv")
file.append("../core/issue_read_operands.sv")
file.append("../core/alu.sv")
file.append("../core/branch_unit.sv")
file.append("../core/csr_buffer.sv")
file.append("../core/mult.sv")
file.append("../core/multiplier.sv")
file.append("../core/serdiv.sv")
file.append("../core/load_store_unit.sv")
file.append("../core/load_unit.sv")
file.append("../core/store_unit.sv")
file.append("../core/lsu_bypass.sv")
file.append("../core/cvxif_fu.sv")
file.append("../core/cache_subsystem/cva6_hpdcache_subsystem.sv")
black_list = define_blacklist(parameters)
for filein in file:
comments = []
a = re.match(r".*\/(.*).sv", filein)
module = a.group(1)
print("Input file " + filein)
ports = []
with open(filein, "r", encoding="utf-8") as fin:
description = "none"
connexion = "none"
for line in fin:
e = re.match(r"^ +(?:(in|out))put +([\S]*(?: +.* *|)) ([\S]*)\n", line)
d = re.match(r"^ +\/\/ (.*) - ([\S]*)\n", line)
if d:
description = d.group(1)
connexion = d.group(2)
if e:
name = e.group(3)
name = name.replace(",", "")
data_type = e.group(2)
data_type = data_type.replace(" ", "")
if connexion in black_list:
for i, comment in enumerate(comments):
if black_list[connexion][0] == comment[0]:
comment[1] = (
comment[1]
+ f"\n| ``{name}`` {e.group(1)}put is tied to {black_list[connexion][1]}"
)
break
else:
comments.append(
[
black_list[connexion][0],
f"``{name}`` {e.group(1)}put is tied to {black_list[connexion][1]}",
]
)
else:
if name in black_list:
for i, comment in enumerate(comments):
if black_list[name][0] == comment[0]:
comment[1] = (
comment[1]
+ f"\n| ``{name}`` {e.group(1)}put is tied to {black_list[name][1]}"
)
break
else:
comments.append(
[
black_list[name][0],
f"``{name}`` {e.group(1)}put is tied to {black_list[name][1]}",
]
)
else:
ports.append(
PortIO(
name, e.group(1), data_type, description, connexion
)
)
description = "none"
connexion = "none"
print_to_adoc(args.gen_ports_folder, target, module, ports, comments)
def export_user_cfg_doc(out_path, params):
with open(out_path, "w", encoding="utf-8") as f:
f.write(HEADER_RST)
f.write("""\
.. _cva6_user_cfg_doc:
.. list-table:: ``cva6_user_cfg_t`` parameters
:header-rows: 1
* - Name
- Type
- Description
""")
for name, param in params.items():
f.write("\n")
f.write(f" * - ``{name}``\n")
f.write(f" - ``{param.datatype.strip()}``\n")
f.write(f" - {param.description}\n")
if __name__ == "__main__":
main()