litex/litex/soc/doc/module.py

123 lines
4.2 KiB
Python

#
# This file is part of LiteX.
#
# Copyright (c) 2020 Sean Cross <sean@xobs.io>
# SPDX-License-Identifier: BSD-2-Clause
from migen.fhdl.module import DUID
from migen.util.misc import xdir
from litex.soc.interconnect.csr_eventmanager import EventManager
from litex.soc.integration.doc import ModuleDoc
import textwrap
from .rst import print_table, print_rst
def gather_submodules_inner(module, depth, seen_modules, submodules):
if module is None:
return submodules
if depth == 0:
if isinstance(module, ModuleDoc):
# print("{} is an instance of ModuleDoc".format(module))
submodules["module_doc"].append(module)
for k,v in module._submodules:
# print("{}Submodule {} {}".format(" "*(depth*4), k, v))
if v not in seen_modules:
seen_modules.add(v)
if isinstance(v, EventManager):
# print("{}{} appears to be an EventManager".format(" "*(depth*4), k))
submodules["event_managers"].append(v)
if isinstance(v, ModuleDoc):
submodules["module_doc"].append(v)
gather_submodules_inner(v, depth + 1, seen_modules, submodules)
return submodules
def gather_submodules(module):
depth = 0
seen_modules = set()
submodules = {
"event_managers": [],
"module_doc": [],
}
return gather_submodules_inner(module, depth, seen_modules, submodules)
class ModuleNotDocumented(Exception):
"""Indicates a Module has no documentation or sub-documentation"""
pass
class DocumentedModule:
"""Multi-section Documentation of a Module"""
def __init__(self, name, module, has_documentation=False):
self.name = name
self.sections = []
if isinstance(module, ModuleDoc):
has_documentation = True
self.sections.append(module)
if hasattr(module, "get_module_documentation"):
for doc in module.get_module_documentation():
has_documentation = True
self.sections.append(doc)
if not has_documentation:
raise ModuleNotDocumented()
def print_region(self, stream, base_dir, note_pulses=False):
title = "{}".format(self.name.upper())
print(title, file=stream)
print("=" * len(title), file=stream)
print("", file=stream)
for section in self.sections:
title = textwrap.dedent(section.title())
body = textwrap.dedent(section.body())
print("{}".format(title), file=stream)
print("-" * len(title), file=stream)
print(textwrap.dedent(body), file=stream)
print("", file=stream)
class DocumentedInterrupts(DocumentedModule):
"""A :obj:`DocumentedModule` that automatically documents interrupts in an SoC
This creates a :obj:`DocumentedModule` object that prints out the contents
of the interrupt map of an SoC.
"""
def __init__(self, interrupts):
DocumentedModule.__init__(self, "interrupts", None, has_documentation=True)
self.irq_table = [["Interrupt", "Module"]]
for module_name, irq_no in interrupts.items():
self.irq_table.append([str(irq_no), ":doc:`{} <{}>`".format(module_name.upper(), module_name)])
def print_region(self, stream, base_dir, note_pulses=False):
title = "Interrupt Controller"
print(title, file=stream)
print("=" * len(title), file=stream)
print("", file=stream)
print_rst(stream,
"""
This device has an ``EventManager``-based interrupt
system. Individual modules generate `events` which are wired
into a central interrupt controller.
When an interrupt occurs, you should look the interrupt number up
in the CPU-specific interrupt table and then call the relevant
module.
""")
section_title = "Assigned Interrupts"
print("{}".format(section_title), file=stream)
print("-" * len(section_title), file=stream)
print("", file=stream)
print("The following interrupts are assigned on this system:", file=stream)
print_table(self.irq_table, stream)