doc: align to improve readability.

This commit is contained in:
Florent Kermarrec 2020-03-04 16:31:41 +01:00
parent 4f935714de
commit 4c83c975b1
3 changed files with 112 additions and 55 deletions

View File

@ -35,9 +35,13 @@ def generate_svd(soc, buildpath, filename=None, name="soc", **kwargs):
svd.write(export.get_svd(soc, **kwargs)) svd.write(export.get_svd(soc, **kwargs))
def generate_docs(soc, base_dir, project_name="LiteX SoC Project", def generate_docs(soc, base_dir,
author="Anonymous", sphinx_extensions=[], quiet=False, note_pulses=False, project_name = "LiteX SoC Project",
from_scratch=True): author = "Anonymous",
sphinx_extensions = [],
quiet = False,
note_pulses = False,
from_scratch = True):
"""Possible extra extensions: """Possible extra extensions:
[ [
'm2r', 'm2r',
@ -79,7 +83,7 @@ def generate_docs(soc, base_dir, project_name="LiteX SoC Project",
# that are larger than the buswidth will be turned into multiple # that are larger than the buswidth will be turned into multiple
# DocumentedCSRs. # DocumentedCSRs.
documented_regions = [] documented_regions = []
seen_modules = set() seen_modules = set()
for name, region in soc.csr.regions.items(): for name, region in soc.csr.regions.items():
module = None module = None
if hasattr(soc, name): if hasattr(soc, name):

View File

@ -34,32 +34,41 @@ class DocumentedCSR:
return reflow(docstring) return reflow(docstring)
return None return None
def __init__(self, name, address, short_numbered_name="", short_name="", reset=0, offset=0, size=8, description=None, access="read-write", fields=[]): def __init__(self, name, address,
self.name = name short_numbered_name = "",
self.short_name = short_name short_name = "",
reset = 0,
offset = 0,
size = 8,
description = None,
access = "read-write",
fields = []):
self.name = name
self.short_name = short_name
self.short_numbered_name = short_numbered_name self.short_numbered_name = short_numbered_name
self.address = address self.address = address
self.offset = offset self.offset = offset
self.size = size self.size = size
if size == 0: if size == 0:
print("!!! Warning: creating CSR of size 0 {}".format(name)) print("!!! Warning: creating CSR of size 0 {}".format(name))
self.description = self.trim(description) self.description = self.trim(description)
self.reset_value = reset self.reset_value = reset
self.fields = fields self.fields = fields
self.access = access self.access = access
for f in self.fields: for f in self.fields:
f.description = self.trim(f.description) f.description = self.trim(f.description)
class DocumentedCSRRegion: class DocumentedCSRRegion:
def __init__(self, name, region, module=None, submodules=[], csr_data_width=8): def __init__(self, name, region, module=None, submodules=[], csr_data_width=8):
self.name = name self.name = name
self.origin = region.origin self.origin = region.origin
self.busword = region.busword self.busword = region.busword
self.raw_csrs = region.obj self.raw_csrs = region.obj
self.current_address = self.origin self.current_address = self.origin
self.sections = [] self.sections = []
self.csrs = [] self.csrs = []
self.csr_data_width = csr_data_width self.csr_data_width = csr_data_width
# If the section has extra documentation, gather it. # If the section has extra documentation, gather it.
if isinstance(module, ModuleDoc): if isinstance(module, ModuleDoc):
@ -81,10 +90,16 @@ class DocumentedCSRRegion:
print("{}: Unknown module: {}".format(self.name, csr)) print("{}: Unknown module: {}".format(self.name, csr))
elif isinstance(self.raw_csrs, Memory): elif isinstance(self.raw_csrs, Memory):
self.csrs.append(DocumentedCSR( self.csrs.append(DocumentedCSR(
self.name.upper(), self.origin, short_numbered_name=self.name.upper(), short_name=self.name.upper(), reset=0, size=self.raw_csrs.width, name = self.name.upper(),
description="{} x {}-bit memory".format(self.raw_csrs.width, self.raw_csrs.depth) address = self.origin,
short_numbered_name = self.name.upper(),
short_name = self.name.upper(),
reset = 0,
size = self.raw_csrs.width,
description = "{} x {}-bit memory".format(self.raw_csrs.width, self.raw_csrs.depth)
)) ))
print("{}@{:x}: Found memory that's {} x {} (but memories aren't documented yet)".format(self.name, self.origin, self.raw_csrs.width, self.raw_csrs.depth)) print("{}@{:x}: Found memory that's {} x {} (but memories aren't documented yet)".format(
self.name, self.origin, self.raw_csrs.width, self.raw_csrs.depth))
else: else:
print("{}@{:x}: Unexpected item on the CSR bus: {}".format(self.name, self.origin, self.raw_csrs)) print("{}@{:x}: Unexpected item on the CSR bus: {}".format(self.name, self.origin, self.raw_csrs))
@ -127,9 +142,15 @@ class DocumentedCSRRegion:
fields = [] fields = []
for i, source in enumerate(sources): for i, source in enumerate(sources):
if hasattr(source, "name") and source.name is not None: if hasattr(source, "name") and source.name is not None:
fields.append(DocumentedCSRField(CSRField(source.name, offset=i, description="Level of the `{}` event".format(source.name)))) fields.append(DocumentedCSRField(CSRField(
name = source.name,
offset = i,
description = "Level of the `{}` event".format(source.name))))
else: else:
fields.append(DocumentedCSRField(CSRField("event{}".format(i), offset=i, description="Level of the `event{}` event".format(i)))) fields.append(DocumentedCSRField(CSRField(
name = "event{}".format(i),
offset = i,
description = "Level of the `event{}` event".format(i))))
dcsr.fields = fields dcsr.fields = fields
if dcsr.description is None: if dcsr.description is None:
dcsr.description = "This register contains the current raw level of the Event trigger. Writes to this register have no effect." dcsr.description = "This register contains the current raw level of the Event trigger. Writes to this register have no effect."
@ -138,9 +159,15 @@ class DocumentedCSRRegion:
fields = [] fields = []
for i, source in enumerate(sources): for i, source in enumerate(sources):
if hasattr(source, "name") and source.name is not None: if hasattr(source, "name") and source.name is not None:
fields.append(DocumentedCSRField(CSRField(source.name, offset=i, description=source_description(source)))) fields.append(DocumentedCSRField(CSRField(
name = source.name,
offset = i,
description = source_description(source))))
else: else:
fields.append(DocumentedCSRField(CSRField("event{}".format(i), offset=i, description=source_description(source)))) fields.append(DocumentedCSRField(CSRField(
name = "event{}".format(i),
offset = i,
description = source_description(source))))
dcsr.fields = fields dcsr.fields = fields
if dcsr.description is None: if dcsr.description is None:
dcsr.description = "When an Event occurs, the corresponding bit will be set in this register. To clear the Event, set the corresponding bit in this register." dcsr.description = "When an Event occurs, the corresponding bit will be set in this register. To clear the Event, set the corresponding bit in this register."
@ -149,18 +176,24 @@ class DocumentedCSRRegion:
fields = [] fields = []
for i, source in enumerate(sources): for i, source in enumerate(sources):
if hasattr(source, "name") and source.name is not None: if hasattr(source, "name") and source.name is not None:
fields.append(DocumentedCSRField(CSRField(source.name, offset=i, description="Write a `1` to enable the `{}` Event".format(source.name)))) fields.append(DocumentedCSRField(CSRField(
name = source.name,
offset = i,
description = "Write a `1` to enable the `{}` Event".format(source.name))))
else: else:
fields.append(DocumentedCSRField(CSRField("event{}".format(i), offset=i, description="Write a `1` to enable the `{}` Event".format(i)))) fields.append(DocumentedCSRField(CSRField(
name = "event{}".format(i),
offset = i,
description = "Write a `1` to enable the `{}` Event".format(i))))
dcsr.fields = fields dcsr.fields = fields
if dcsr.description is None: if dcsr.description is None:
dcsr.description = "This register enables the corresponding Events. Write a `0` to this register to disable individual events." dcsr.description = "This register enables the corresponding Events. Write a `0` to this register to disable individual events."
def sub_csr_bit_range(self, csr, offset): def sub_csr_bit_range(self, csr, offset):
nwords = (csr.size + self.busword - 1)//self.busword nwords = (csr.size + self.busword - 1)//self.busword
i = nwords - offset - 1 i = nwords - offset - 1
nbits = min(csr.size - i*self.busword, self.busword) - 1 nbits = min(csr.size - i*self.busword, self.busword) - 1
name = (csr.name + str(i) if nwords > 1 else csr.name).upper() name = (csr.name + str(i) if nwords > 1 else csr.name).upper()
origin = i*self.busword origin = i*self.busword
return (origin, nbits, name) return (origin, nbits, name)
@ -268,11 +301,11 @@ class DocumentedCSRRegion:
def document_csr(self, csr): def document_csr(self, csr):
"""Generates one or more DocumentedCSR, which will get appended """Generates one or more DocumentedCSR, which will get appended
to self.csrs""" to self.csrs"""
fields = [] fields = []
description = None description = None
atomic_write = False atomic_write = False
full_name = self.name.upper() + "_" + csr.name.upper() full_name = self.name.upper() + "_" + csr.name.upper()
reset = 0 reset = 0
if isinstance(csr, CSRStatus): if isinstance(csr, CSRStatus):
access = "read-only" access = "read-only"
else: else:
@ -306,28 +339,49 @@ class DocumentedCSRRegion:
else: else:
d = bits_str + " " + reflow(d) d = bits_str + " " + reflow(d)
self.csrs.append(DocumentedCSR( self.csrs.append(DocumentedCSR(
sub_name, self.current_address, short_numbered_name=name.upper(), short_name=csr.name.upper(), reset=(reset>>start)&((2**length)-1), name = sub_name,
offset=start, size=self.csr_data_width, address = self.current_address,
description=d, fields=self.split_fields(fields, start, start + length), access=access short_numbered_name = name.upper(),
short_name = csr.name.upper(),
reset = (reset>>start)&((2**length)-1),
offset = start,
size = self.csr_data_width,
description = d,
fields = self.split_fields(fields, start, start + length),
access = access
)) ))
else: else:
self.csrs.append(DocumentedCSR( self.csrs.append(DocumentedCSR(
sub_name, self.current_address, short_numbered_name=name.upper(), short_name=csr.name.upper(), reset=(reset>>start)&((2**length)-1), name = sub_name,
offset=start, size=self.csr_data_width, address = self.current_address,
description=bits_str, fields=self.split_fields(fields, start, start + length), access=access short_numbered_name = name.upper(),
short_name = csr.name.upper(),
reset = (reset>>start)&((2**length)-1),
offset = start,
size = self.csr_data_width,
description = bits_str,
fields = self.split_fields(fields, start, start + length),
access = access
)) ))
self.current_address += 4 self.current_address += 4
else: else:
self.csrs.append(DocumentedCSR( self.csrs.append(DocumentedCSR(
full_name, self.current_address, short_numbered_name=csr.name.upper(), short_name=csr.name.upper(), reset=reset, size=size, name = full_name,
description=description, fields=fields, access=access address = self.current_address,
short_numbered_name = csr.name.upper(),
short_name = csr.name.upper(),
reset = reset,
size = size,
description = description,
fields = fields,
access = access
)) ))
self.current_address += 4 self.current_address += 4
def make_value_table(self, values): def make_value_table(self, values):
ret = "" ret = ""
max_value_width=len("Value") max_value_width = len("Value")
max_description_width=len("Description") max_description_width = len("Description")
for v in values: for v in values:
(value, name, description) = (None, None, None) (value, name, description) = (None, None, None)
if len(v) == 2: if len(v) == 2:
@ -380,7 +434,7 @@ class DocumentedCSRRegion:
for section in self.sections: for section in self.sections:
title = textwrap.dedent(section.title()) title = textwrap.dedent(section.title())
body = textwrap.dedent(section.body()) body = textwrap.dedent(section.body())
print("{}".format(title), file=stream) print("{}".format(title), file=stream)
print("-" * len(title), file=stream) print("-" * len(title), file=stream)
@ -417,11 +471,10 @@ class DocumentedCSRRegion:
print(textwrap.indent(csr.description, prefix=" "), file=stream) print(textwrap.indent(csr.description, prefix=" "), file=stream)
self.print_reg(csr, stream) self.print_reg(csr, stream)
if len(csr.fields) > 0: if len(csr.fields) > 0:
max_field_width=len("Field") max_field_width = len("Field")
max_name_width=len("Name") max_name_width = len("Name")
max_description_width=len("Description") max_description_width = len("Description")
value_tables = {} value_tables = {}
for f in csr.fields: for f in csr.fields:
field = self.bit_range(f.offset, f.offset + f.size) field = self.bit_range(f.offset, f.offset + f.size)
max_field_width = max(max_field_width, len(field)) max_field_width = max(max_field_width, len(field))

View File

@ -33,9 +33,9 @@ def gather_submodules_inner(module, depth, seen_modules, submodules):
return submodules return submodules
def gather_submodules(module): def gather_submodules(module):
depth = 0 depth = 0
seen_modules = set() seen_modules = set()
submodules = { submodules = {
"event_managers": [], "event_managers": [],
"module_doc": [], "module_doc": [],
} }
@ -50,7 +50,7 @@ class DocumentedModule:
"""Multi-section Documentation of a Module""" """Multi-section Documentation of a Module"""
def __init__(self, name, module, has_documentation=False): def __init__(self, name, module, has_documentation=False):
self.name = name self.name = name
self.sections = [] self.sections = []
if isinstance(module, ModuleDoc): if isinstance(module, ModuleDoc):