Skip to content

Commit 8574b04

Browse files
Synchronize Memory requirements tables
Updated scripts for generating memory requirements and updated CSS files. Signed-off-by: Arkadiusz Balys <arkadiusz.balys@nordicsemi.no>
1 parent 8dae784 commit 8574b04

27 files changed

Lines changed: 4265 additions & 6263 deletions

docs/_extensions/memory_data.py

Lines changed: 617 additions & 116 deletions
Large diffs are not rendered by default.

docs/_extensions/memory_layout_viz.py

Lines changed: 139 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
44
SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
55
6-
Sphinx extension for partition layout bar charts.
7-
6+
Sphinx extension for Matter reference partition layout bar charts.
87
"""
98

109
from __future__ import annotations
@@ -17,7 +16,7 @@
1716
from docutils import nodes
1817
from docutils.parsers.rst import directives
1918
from docutils.statemachine import StringList
20-
from memory_data import load_memory_yaml, plain_tab_label, sort_boards_by_internal_memory
19+
from memory_data import load_board_data
2120
from sphinx.application import Sphinx
2221
from sphinx.util.docutils import SphinxDirective
2322

@@ -38,14 +37,14 @@
3837
"#65a30d",
3938
]
4039

41-
4240
_LAYOUT_FIXED_COLORS = {
4341
"padding": "#e2e8f0",
4442
"boot_partition": "#2563eb",
4543
"slot0_partition": "#16a34a",
4644
"slot1_partition": "#0369a1",
4745
"factory_data_partition": "#ea580c",
4846
"storage_partition": "#ca8a04",
47+
"tfm_storage_partition": "#0d9488",
4948
}
5049

5150
TOOLTIP_ALIGN_START_THRESHOLD_PCT = 20.0
@@ -70,7 +69,6 @@ def _hex_label(size_bytes: int) -> str:
7069

7170

7271
def _display_widths(sizes_bytes: list[int]) -> list[float]:
73-
"""Map partition sizes to bar widths proportional to byte size."""
7472
if not sizes_bytes:
7573
return []
7674
total = sum(max(size, 0) for size in sizes_bytes) or 1
@@ -201,63 +199,155 @@ def _render_region_html(region: dict[str, Any]) -> str:
201199
)
202200

203201

204-
def _render_board_layout_html(board: dict[str, Any]) -> str:
205-
regions = "".join(_render_region_html(region) for region in board.get("regions", []))
202+
def _format_offset(offset_bytes: int) -> str:
203+
return f"{offset_bytes} (0x{offset_bytes:x})"
204+
205+
206+
def _format_size(size_bytes: int) -> str:
207+
return f"{_bytes_label(size_bytes)} ({_hex_label(size_bytes)})"
208+
209+
210+
def _iter_partition_rows(
211+
partitions: list[dict[str, Any]],
212+
*,
213+
depth: int = 0,
214+
) -> list[tuple[str, int, int]]:
215+
rows: list[tuple[str, int, int]] = []
216+
indent = " " * depth
217+
for part in partitions:
218+
rows.append((f"{indent}{part['label']}", int(part["offset_bytes"]), int(part["size_bytes"])))
219+
children = part.get("children") or []
220+
if children:
221+
rows.extend(_iter_partition_rows(children, depth=depth + 1))
222+
return rows
223+
224+
225+
def _append_rst_paragraph(state, parent: nodes.Element, rst_text: str) -> None:
226+
paragraph = nodes.paragraph()
227+
content = StringList([rst_text], "<memory_layout_table>")
228+
state.nested_parse(content, 0, paragraph)
229+
if len(paragraph) == 1 and isinstance(paragraph[0], nodes.paragraph):
230+
inner = paragraph[0]
231+
paragraph.remove(inner)
232+
paragraph.extend(inner.children)
233+
parent += paragraph
234+
235+
236+
def _build_region_table(region: dict[str, Any]) -> nodes.table:
237+
table = nodes.table()
238+
table["classes"] = ["memory-layout-table"]
239+
240+
tgroup = nodes.tgroup(cols=3)
241+
table += tgroup
242+
tgroup.extend([nodes.colspec(colwidth=24), nodes.colspec(colwidth=12), nodes.colspec(colwidth=12)])
243+
244+
thead = nodes.thead()
245+
tgroup += thead
246+
header_row = nodes.row()
247+
thead += header_row
248+
for title in ("Partition", "Offset", "Size"):
249+
entry = nodes.entry()
250+
entry += nodes.Text(title)
251+
header_row += entry
252+
253+
tbody = nodes.tbody()
254+
tgroup += tbody
255+
for label, offset_bytes, size_bytes in _iter_partition_rows(region.get("partitions") or []):
256+
row = nodes.row()
257+
tbody += row
258+
259+
label_entry = nodes.entry()
260+
label_entry += nodes.Text(label)
261+
row += label_entry
262+
263+
offset_entry = nodes.entry()
264+
offset_entry += nodes.Text(_format_offset(offset_bytes))
265+
row += offset_entry
266+
267+
size_entry = nodes.entry()
268+
size_entry += nodes.Text(_format_size(size_bytes))
269+
row += size_entry
270+
271+
return table
272+
273+
274+
def build_layout_table_nodes(directive: SphinxDirective, data: dict[str, Any]) -> nodes.Element:
275+
wrapper = nodes.container()
276+
wrapper["classes"] = ["memory-layout-table-board"]
277+
278+
regions = data.get("reference_regions") or []
279+
for index, region in enumerate(regions):
280+
if index:
281+
wrapper += nodes.raw("", '<div class="memory-layout-table-region-spacer"></div>', format="html")
282+
283+
total_bytes = int(region["total_bytes"])
284+
title = nodes.paragraph()
285+
title["classes"] = ["memory-layout-table-region-title"]
286+
emphasis = nodes.strong()
287+
emphasis += nodes.Text(
288+
f'{region["title"]} (size: {_hex_label(total_bytes)} = {_bytes_label(total_bytes)})'
289+
)
290+
title += emphasis
291+
wrapper += title
292+
293+
if region.get("address_note_rst"):
294+
_append_rst_paragraph(directive.state, wrapper, str(region["address_note_rst"]))
295+
296+
wrapper += _build_region_table(region)
297+
298+
return wrapper
299+
300+
301+
def _render_board_layout_html(data: dict[str, Any]) -> str:
302+
regions = "".join(_render_region_html(region) for region in data.get("reference_regions", []))
303+
board_name = data.get("board", {}).get("name", "")
206304
return (
207305
f'<div class="memory-layout-board" '
208-
f'data-board="{html.escape(board["board_id"], quote=True)}">'
306+
f'data-board="{html.escape(board_name, quote=True)}">'
209307
f"{regions}</div>"
210308
)
211309

212310

213-
def _build_layout_tabs_rst(
214-
directive: SphinxDirective,
215-
boards: list[dict[str, Any]],
216-
render_fn,
217-
empty_message: str,
218-
) -> list[nodes.Node]:
219-
if not boards:
220-
note = nodes.paragraph()
221-
note += nodes.emphasis(text=empty_message)
222-
return [note]
223-
224-
lines = [".. tabs::", ""]
225-
for board in boards:
226-
lines.append(f" .. group-tab:: {plain_tab_label(board['tab_title'])}")
227-
lines.append("")
228-
for intro_line in board.get("tab_intro_rst", "").splitlines():
229-
lines.append(f" {intro_line}")
230-
lines.append("")
231-
lines.append(" .. raw:: html")
232-
lines.append("")
233-
for html_line in render_fn(board).splitlines():
234-
lines.append(f" {html_line}")
235-
lines.append("")
236-
237-
container = nodes.container()
238-
directive.state.nested_parse(StringList(lines, "<memory_layout>"), 0, container)
239-
return container.children
240-
241-
242-
class MemoryLayouts(SphinxDirective):
243-
"""Render reference memory layout charts from a YAML data file."""
311+
class MemoryLayoutBoard(SphinxDirective):
312+
"""Render reference memory layout charts from docs/data/memory/<board>.yaml."""
244313

245314
required_arguments = 0
246315
optional_arguments = 0
247316
final_argument_whitespace = True
248317
has_content = False
249318
option_spec = {
250-
"file": directives.unchanged_required,
319+
"board": directives.unchanged_required,
251320
}
252321

253322
def run(self) -> list[nodes.Node]:
254-
data = load_memory_yaml(self, self.options["file"])
255-
return _build_layout_tabs_rst(
256-
self,
257-
sort_boards_by_internal_memory(data.get("boards", [])),
258-
_render_board_layout_html,
259-
"No memory layout data found.",
260-
)
323+
data = load_board_data(self.options["board"])
324+
if not data.get("reference_regions"):
325+
note = nodes.paragraph()
326+
note += nodes.emphasis(text="No memory layout data found.")
327+
return [note]
328+
container = nodes.container()
329+
container += nodes.raw("", _render_board_layout_html(data), format="html")
330+
return [container]
331+
332+
333+
class MemoryLayoutTable(SphinxDirective):
334+
"""Render reference memory layout tables from docs/data/memory/<board>.yaml."""
335+
336+
required_arguments = 0
337+
optional_arguments = 0
338+
final_argument_whitespace = True
339+
has_content = False
340+
option_spec = {
341+
"board": directives.unchanged_required,
342+
}
343+
344+
def run(self) -> list[nodes.Node]:
345+
data = load_board_data(self.options["board"])
346+
if not data.get("reference_regions"):
347+
note = nodes.paragraph()
348+
note += nodes.emphasis(text="No memory layout data found.")
349+
return [note]
350+
return [build_layout_table_nodes(self, data)]
261351

262352

263353
def add_memory_layout_viz_resources(app: Sphinx) -> None:
@@ -268,7 +358,8 @@ def add_memory_layout_viz_resources(app: Sphinx) -> None:
268358

269359

270360
def setup(app: Sphinx) -> dict[str, Any]:
271-
app.add_directive("memory-layouts", MemoryLayouts)
361+
app.add_directive("memory-layout-board", MemoryLayoutBoard)
362+
app.add_directive("memory-layout-table", MemoryLayoutTable)
272363
app.connect("builder-inited", add_memory_layout_viz_resources)
273364
return {
274365
"version": __version__,

0 commit comments

Comments
 (0)