From 73ed7e564cc27654015822e892af48c3e51f6a74 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 4 Feb 2020 20:34:10 +0800 Subject: [PATCH] soc: doc: use sphinx toctree as it was intended The sphinx toctree was behaving oddly, and so previously we were ignoring it completely. This patch causes it to be used correctly, which removes the need for double-including various sections. Signed-off-by: Sean Cross --- litex/soc/doc/__init__.py | 163 ++++++++++++++++++++++++-------------- 1 file changed, 102 insertions(+), 61 deletions(-) diff --git a/litex/soc/doc/__init__.py b/litex/soc/doc/__init__.py index 6262c575e..0a8c15dbb 100644 --- a/litex/soc/doc/__init__.py +++ b/litex/soc/doc/__init__.py @@ -10,7 +10,7 @@ from .csr import DocumentedCSRRegion from .module import gather_submodules, ModuleNotDocumented, DocumentedModule, DocumentedInterrupts from .rst import reflow -sphinx_configuration = """ +default_sphinx_configuration = """ project = '{}' copyright = '{}, {}' author = '{}' @@ -26,6 +26,7 @@ html_theme = 'alabaster' html_static_path = ['_static'] """ + def sub_csr_bit_range(busword, csr, offset): nwords = (csr.size + busword - 1)//busword i = nwords - offset - 1 @@ -34,13 +35,17 @@ def sub_csr_bit_range(busword, csr, offset): origin = i*busword return (origin, nbits, name) + def print_svd_register(csr, csr_address, description, length, svd): print(' ', file=svd) print(' {}'.format(csr.short_numbered_name), file=svd) if description is not None: - print(' '.format(description), file=svd) - print(' 0x{:04x}'.format(csr_address), file=svd) - print(' 0x{:02x}'.format(csr.reset_value), file=svd) + print( + ' '.format(description), file=svd) + print( + ' 0x{:04x}'.format(csr_address), file=svd) + print( + ' 0x{:02x}'.format(csr.reset_value), file=svd) print(' {}'.format(length), file=svd) print(' {}'.format(csr.access), file=svd) csr_address = csr_address + 4 @@ -48,11 +53,16 @@ def print_svd_register(csr, csr_address, description, length, svd): if hasattr(csr, "fields") and len(csr.fields) > 0: for field in csr.fields: print(' ', file=svd) - print(' {}'.format(field.name), file=svd) - print(' {}'.format(field.offset + field.size - 1), file=svd) - print(' [{}:{}]'.format(field.offset + field.size - 1, field.offset), file=svd) - print(' {}'.format(field.offset), file=svd) - print(' '.format(reflow(field.description)), file=svd) + print( + ' {}'.format(field.name), file=svd) + print(' {}'.format(field.offset + + field.size - 1), file=svd) + print(' [{}:{}]'.format( + field.offset + field.size - 1, field.offset), file=svd) + print( + ' {}'.format(field.offset), file=svd) + print(' '.format( + reflow(field.description)), file=svd) print(' ', file=svd) else: field_size = csr.size @@ -67,12 +77,14 @@ def print_svd_register(csr, csr_address, description, length, svd): print(' ', file=svd) print(' {}'.format(field_name), file=svd) print(' {}'.format(field_size - 1), file=svd) - print(' [{}:{}]'.format(field_size - 1, 0), file=svd) + print( + ' [{}:{}]'.format(field_size - 1, 0), file=svd) print(' {}'.format(0), file=svd) print(' ', file=svd) print(' ', file=svd) print(' ', file=svd) + def generate_svd(soc, buildpath, vendor="litex", name="soc", filename=None, description=None): interrupts = {} for csr, irq in sorted(soc.soc_interrupt_map.items()): @@ -85,9 +97,11 @@ def generate_svd(soc, buildpath, vendor="litex", name="soc", filename=None, desc raw_regions = soc.get_csr_regions() else: for region_name, region in soc.csr_regions.items(): - raw_regions.append((region_name, region.origin, region.busword, region.obj)) + raw_regions.append((region_name, region.origin, + region.busword, region.obj)) for csr_region in raw_regions: - documented_regions.append(DocumentedCSRRegion(csr_region, csr_data_width=soc.csr_data_width)) + documented_regions.append(DocumentedCSRRegion( + csr_region, csr_data_width=soc.csr_data_width)) if filename is None: filename = name + ".svd" @@ -98,7 +112,8 @@ def generate_svd(soc, buildpath, vendor="litex", name="soc", filename=None, desc print(' {}'.format(vendor), file=svd) print(' {}'.format(name.upper()), file=svd) if description is not None: - print(' '.format(reflow(description)), file=svd) + print( + ' '.format(reflow(description)), file=svd) print('', file=svd) print(' 8', file=svd) print(' 32', file=svd) @@ -113,10 +128,13 @@ def generate_svd(soc, buildpath, vendor="litex", name="soc", filename=None, desc csr_address = 0 print(' ', file=svd) print(' {}'.format(region.name.upper()), file=svd) - print(' 0x{:08X}'.format(region.origin), file=svd) - print(' {}'.format(region.name.upper()), file=svd) + print( + ' 0x{:08X}'.format(region.origin), file=svd) + print( + ' {}'.format(region.name.upper()), file=svd) if len(region.sections) > 0: - print(' '.format(reflow(region.sections[0].body())), file=svd) + print(' '.format( + reflow(region.sections[0].body())), file=svd) print(' ', file=svd) for csr in region.csrs: description = None @@ -125,42 +143,53 @@ def generate_svd(soc, buildpath, vendor="litex", name="soc", filename=None, desc if isinstance(csr, _CompoundCSR) and len(csr.simple_csrs) > 1: is_first = True for i in range(len(csr.simple_csrs)): - (start, length, name) = sub_csr_bit_range(region.busword, csr, i) - sub_name = csr.name.upper() + "_" + name + (start, length, name) = sub_csr_bit_range( + region.busword, csr, i) if length > 0: - bits_str = "Bits {}-{} of `{}`.".format(start, start+length, csr.name) + bits_str = "Bits {}-{} of `{}`.".format( + start, start+length, csr.name) else: - bits_str = "Bit {} of `{}`.".format(start, csr.name) + bits_str = "Bit {} of `{}`.".format( + start, csr.name) if is_first: if description is not None: - print_svd_register(csr.simple_csrs[i], csr_address, bits_str + " " + description, length, svd) + print_svd_register( + csr.simple_csrs[i], csr_address, bits_str + " " + description, length, svd) else: - print_svd_register(csr.simple_csrs[i], csr_address, bits_str, length, svd) + print_svd_register( + csr.simple_csrs[i], csr_address, bits_str, length, svd) is_first = False else: - print_svd_register(csr.simple_csrs[i], csr_address, bits_str, length, svd) + print_svd_register( + csr.simple_csrs[i], csr_address, bits_str, length, svd) csr_address = csr_address + 4 else: - length = ((csr.size + region.busword - 1)//region.busword) * region.busword - print_svd_register(csr, csr_address, description, length, svd) + length = ((csr.size + region.busword - 1) // + region.busword) * region.busword + print_svd_register( + csr, csr_address, description, length, svd) csr_address = csr_address + 4 print(' ', file=svd) print(' ', file=svd) print(' 0', file=svd) - print(' 0x{:x}'.format(csr_address), file=svd) + print( + ' 0x{:x}'.format(csr_address), file=svd) print(' registers', file=svd) print(' ', file=svd) if region.name in interrupts: print(' ', file=svd) print(' {}'.format(region.name), file=svd) - print(' {}'.format(interrupts[region.name]), file=svd) + print( + ' {}'.format(interrupts[region.name]), file=svd) print(' ', file=svd) print(' ', file=svd) print(' ', file=svd) print('', file=svd) + def generate_docs(soc, base_dir, project_name="LiteX SoC Project", - author="Anonymous", sphinx_extensions=[], quiet=False, note_pulses=False): + author="Anonymous", sphinx_extensions=[], quiet=False, note_pulses=False, + from_scratch=True): """Possible extra extensions: [ 'm2r', @@ -177,13 +206,17 @@ def generate_docs(soc, base_dir, project_name="LiteX SoC Project", # Ensure the output directory exists pathlib.Path(base_dir + "/_static").mkdir(parents=True, exist_ok=True) - # Create various Sphinx plumbing - with open(base_dir + "conf.py", "w", encoding="utf-8") as conf: - year = datetime.datetime.now().year - sphinx_ext_str = "" - for ext in sphinx_extensions: - sphinx_ext_str += "\n \"{}\",".format(ext) - print(sphinx_configuration.format(project_name, year, author, author, sphinx_ext_str), file=conf) + # Create the sphinx configuration file if the user has requested, + # or if it doesn't exist already. + if from_scratch or not os.path.isfile(base_dir + "conf.py"): + with open(base_dir + "conf.py", "w", encoding="utf-8") as conf: + year = datetime.datetime.now().year + sphinx_ext_str = "" + for ext in sphinx_extensions: + sphinx_ext_str += "\n \"{}\",".format(ext) + print(default_sphinx_configuration.format(project_name, year, + author, author, sphinx_ext_str), file=conf) + if not quiet: print("Generate the documentation by running `sphinx-build -M html {} {}_build`".format(base_dir, base_dir)) @@ -200,13 +233,16 @@ def generate_docs(soc, base_dir, project_name="LiteX SoC Project", documented_regions = [] seen_modules = set() regions = [] + # Previously, litex contained a function to gather csr regions. if hasattr(soc, "get_csr_regions"): regions = soc.get_csr_regions() else: # Now we just access the regions directly. for region_name, region in soc.csr_regions.items(): - regions.append((region_name, region.origin, region.busword, region.obj)) + regions.append((region_name, region.origin, + region.busword, region.obj)) + for csr_region in regions: module = None if hasattr(soc, csr_region[0]): @@ -214,9 +250,11 @@ def generate_docs(soc, base_dir, project_name="LiteX SoC Project", seen_modules.add(module) submodules = gather_submodules(module) - documented_region = DocumentedCSRRegion(csr_region, module, submodules, csr_data_width=soc.csr_data_width) + documented_region = DocumentedCSRRegion( + csr_region, module, submodules, csr_data_width=soc.csr_data_width) if documented_region.name in interrupts: - documented_region.document_interrupt(soc, submodules, interrupts[documented_region.name]) + documented_region.document_interrupt( + soc, submodules, interrupts[documented_region.name]) documented_regions.append(documented_region) # Document any modules that are not CSRs. @@ -231,38 +269,41 @@ def generate_docs(soc, base_dir, project_name="LiteX SoC Project", except ModuleNotDocumented: pass - with open(base_dir + "index.rst", "w", encoding="utf-8") as index: - print(""" + # Create index.rst containing links to all of the generated files. + # If the user has set `from_scratch=False`, then skip this step. + if from_scratch or not os.path.isfile(base_dir + "index.rst"): + with open(base_dir + "index.rst", "w", encoding="utf-8") as index: + print(""" Documentation for {} {} -.. toctree:: - :hidden: """.format(project_name, "="*len("Documentation for " + project_name)), file=index) - for module in additional_modules: - print(" {}".format(module.name), file=index) - for region in documented_regions: - print(" {}".format(region.name), file=index) - if len(additional_modules) > 0: - print(""" + if len(additional_modules) > 0: + print(""" Modules -======= -""", file=index) - for module in additional_modules: - print("* :doc:`{} <{}>`".format(module.name.upper(), module.name), file=index) +------- - if len(documented_regions) > 0: - print(""" +.. toctree:: + :maxdepth: 1 +""", file=index) + for module in additional_modules: + print(" {}".format(module.name), file=index) + + if len(documented_regions) > 0: + print(""" Register Groups -=============== -""", file=index) - for region in documented_regions: - print("* :doc:`{} <{}>`".format(region.name.upper(), region.name), file=index) +--------------- - print(""" +.. toctree:: + :maxdepth: 1 +""", file=index) + for region in documented_regions: + print(" {}".format(region.name), file=index) + + print(""" Indices and tables -================== +------------------ * :ref:`genindex` * :ref:`modindex` @@ -279,10 +320,10 @@ Indices and tables with open(base_dir + region.name + ".rst", "w", encoding="utf-8") as outfile: region.print_region(outfile, base_dir, note_pulses) + # Copy over wavedrom javascript and configuration files with open(os.path.dirname(__file__) + "/static/WaveDrom.js", "r") as wd_in: with open(base_dir + "/_static/WaveDrom.js", "w") as wd_out: wd_out.write(wd_in.read()) - with open(os.path.dirname(__file__) + "/static/default.js", "r") as wd_in: with open(base_dir + "/_static/default.js", "w") as wd_out: wd_out.write(wd_in.read())