Skip to content

Commit 05f167e

Browse files
etterlih-filali
authored andcommitted
[otbn,doc] Extend ISR description with bit fields
This extends the CSR/WSR description such that bit fields can be described. Previously only single bits could be described. This extends the documentation generation scripts for bit fields. Signed-off-by: Pascal Etterli <[email protected]>
1 parent d24a0bd commit 05f167e

File tree

4 files changed

+210
-26
lines changed

4 files changed

+210
-26
lines changed

hw/ip/otbn/README.md

Lines changed: 114 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,36 @@ All read-write (RW) CSRs are set to 0 when OTBN starts an operation (when 1 is w
135135
<tr><th>Bit</th><th>Description</th></tr>
136136
</thead>
137137
<tbody>
138-
<tr><td>0</td><td>Carry of flag group 0</td></tr>
139-
<tr><td>1</td><td>MSb of flag group 0</td></tr>
140-
<tr><td>2</td><td>LSb of flag group 0</td></tr>
141-
<tr><td>3</td><td>Zero of flag group 0</td></tr>
138+
<tr>
139+
<td>0</td>
140+
<td>
141+
Carry of flag group 0
142+
</td>
143+
</tr>
144+
<tr>
145+
<td>1</td>
146+
<td>
147+
MSb of flag group 0
148+
</td>
149+
</tr>
150+
<tr>
151+
<td>2</td>
152+
<td>
153+
LSb of flag group 0
154+
</td>
155+
</tr>
156+
<tr>
157+
<td>3</td>
158+
<td>
159+
Zero of flag group 0
160+
</td>
161+
</tr>
162+
<tr>
163+
<td>31:4</td>
164+
<td>
165+
Reserved. Always reads as 0. Any write is ignored.
166+
</td>
167+
</tr>
142168
</tbody>
143169
</table>
144170
</td>
@@ -156,10 +182,36 @@ All read-write (RW) CSRs are set to 0 when OTBN starts an operation (when 1 is w
156182
<tr><th>Bit</th><th>Description</th></tr>
157183
</thead>
158184
<tbody>
159-
<tr><td>0</td><td>Carry of flag group 1</td></tr>
160-
<tr><td>1</td><td>MSb of flag group 1</td></tr>
161-
<tr><td>2</td><td>LSb of flag group 1</td></tr>
162-
<tr><td>3</td><td>Zero of flag group 1</td></tr>
185+
<tr>
186+
<td>0</td>
187+
<td>
188+
Carry of flag group 1
189+
</td>
190+
</tr>
191+
<tr>
192+
<td>1</td>
193+
<td>
194+
MSb of flag group 1
195+
</td>
196+
</tr>
197+
<tr>
198+
<td>2</td>
199+
<td>
200+
LSb of flag group 1
201+
</td>
202+
</tr>
203+
<tr>
204+
<td>3</td>
205+
<td>
206+
Zero of flag group 1
207+
</td>
208+
</tr>
209+
<tr>
210+
<td>31:4</td>
211+
<td>
212+
Reserved. Always reads as 0. Any write is ignored.
213+
</td>
214+
</tr>
163215
</tbody>
164216
</table>
165217
</td>
@@ -177,14 +229,60 @@ All read-write (RW) CSRs are set to 0 when OTBN starts an operation (when 1 is w
177229
<tr><th>Bit</th><th>Description</th></tr>
178230
</thead>
179231
<tbody>
180-
<tr><td>0</td><td>Carry of flag group 0</td></tr>
181-
<tr><td>1</td><td>MSb of flag group 0</td></tr>
182-
<tr><td>2</td><td>LSb of flag group 0</td></tr>
183-
<tr><td>3</td><td>Zero of flag group 0</td></tr>
184-
<tr><td>4</td><td>Carry of flag group 1</td></tr>
185-
<tr><td>5</td><td>MSb of flag group 1</td></tr>
186-
<tr><td>6</td><td>LSb of flag group 1</td></tr>
187-
<tr><td>7</td><td>Zero of flag group 1</td></tr>
232+
<tr>
233+
<td>0</td>
234+
<td>
235+
Carry of flag group 0
236+
</td>
237+
</tr>
238+
<tr>
239+
<td>1</td>
240+
<td>
241+
MSb of flag group 0
242+
</td>
243+
</tr>
244+
<tr>
245+
<td>2</td>
246+
<td>
247+
LSb of flag group 0
248+
</td>
249+
</tr>
250+
<tr>
251+
<td>3</td>
252+
<td>
253+
Zero of flag group 0
254+
</td>
255+
</tr>
256+
<tr>
257+
<td>4</td>
258+
<td>
259+
Carry of flag group 1
260+
</td>
261+
</tr>
262+
<tr>
263+
<td>5</td>
264+
<td>
265+
MSb of flag group 1
266+
</td>
267+
</tr>
268+
<tr>
269+
<td>6</td>
270+
<td>
271+
LSb of flag group 1
272+
</td>
273+
</tr>
274+
<tr>
275+
<td>7</td>
276+
<td>
277+
Zero of flag group 1
278+
</td>
279+
</tr>
280+
<tr>
281+
<td>31:8</td>
282+
<td>
283+
Reserved. Always reads as 0. Any write is ignored.
284+
</td>
285+
</tr>
188286
</tbody>
189287
</table>
190288
</td>

hw/ip/otbn/data/csr.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
1: MSb of flag group 0
1414
2: LSb of flag group 0
1515
3: Zero of flag group 0
16+
31-4: Reserved. Always reads as 0. Any write is ignored.
1617

1718
- name: fg1
1819
address: 0x7c1
@@ -25,6 +26,7 @@
2526
1: MSb of flag group 1
2627
2: LSb of flag group 1
2728
3: Zero of flag group 1
29+
31-4: Reserved. Always reads as 0. Any write is ignored.
2830

2931
- name: flags
3032
address: 0x7c8
@@ -41,6 +43,7 @@
4143
5: MSb of flag group 1
4244
6: LSb of flag group 1
4345
7: Zero of flag group 1
46+
31-8: Reserved. Always reads as 0. Any write is ignored.
4447

4548
- name: mod0
4649
address: 0x7d0

hw/ip/otbn/util/docs/md_isrs.py

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@
99
import argparse
1010
import os
1111
import sys
12-
from typing import List
12+
from typing import Dict, List
13+
14+
# Ensure that the OpenTitan utils directory is on sys.path. This will allow us
15+
# to import serialize.parse_helpers.
16+
_OTBN_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), '../..'))
17+
_OT_DIR = os.path.normpath(os.path.join(_OTBN_DIR, '../../..'))
18+
_OT_UTIL_DIR = os.path.join(_OT_DIR, 'util')
19+
sys.path.append(_OT_UTIL_DIR)
20+
from serialize.parse_helpers import check_keys, check_str, check_int # noqa: E402
1321

1422
sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__),
1523
'../../util')))
@@ -26,6 +34,26 @@ def print_thead(indent: str, columns: List[str]) -> None:
2634
print(f'{indent}</thead>')
2735

2836

37+
def validate_bits(name: str, bits: Dict[str, object]) -> None:
38+
for idx, doc in bits.items():
39+
# For the actual bit description, we expect either:
40+
# - a string for a single bit or a field without values
41+
# - a dict for a field with values
42+
if not (isinstance(doc, str) or isinstance(doc, dict)):
43+
raise ValueError(f'Invalid description format for bit {idx!r} in ISR {name!r}.')
44+
45+
# If it is a single bit or a field without values, there is nothing more to check.
46+
# If we have a bit field with values, check it.
47+
if isinstance(doc, dict):
48+
doc = check_keys(doc, f'bit field {idx} of ISR {name!r}', ['doc', 'values'], [])
49+
# Check the description and values format
50+
check_str(doc['doc'], f'description of bit field {idx} of ISR {name!r}')
51+
assert isinstance(doc['values'], dict)
52+
for k, v in doc['values'].items():
53+
check_int(k, f'value index of ISR {name!r}')
54+
check_str(v, f'description of value {v} in bit field of ISR {name!r}')
55+
56+
2957
def print_isr(indent: str, isr: Isr, add_anchors: bool) -> None:
3058
uc_name = isr.name.upper()
3159
lc_key = isr.name.lower().replace('_', '-')
@@ -41,13 +69,44 @@ def print_isr(indent: str, isr: Isr, add_anchors: bool) -> None:
4169

4270
doc_lines = isr.doc.splitlines()
4371
if isr.bits:
72+
validate_bits(uc_name, isr.bits)
73+
4474
doc_lines += ['<table>',
4575
' <thead>',
4676
' <tr><th>Bit</th><th>Description</th></tr>',
4777
' </thead>',
4878
' <tbody>']
49-
for k, v in isr.bits.items():
50-
doc_lines.append(f' <tr><td>{k}</td><td>{v}</td></tr>')
79+
80+
bit_lines = []
81+
for idx, doc in isr.bits.items():
82+
idx_formatted = idx.replace("-", ":")
83+
doc_raw = doc["doc"] if isinstance(doc, dict) else doc
84+
doc_no_newlines = doc_raw.replace("\n", " ").strip()
85+
86+
bit_lines += ['<tr>']
87+
if isinstance(doc, str):
88+
# We have a single bit or a bit field without values
89+
bit_lines += [f' <td>{idx_formatted}</td>',
90+
' <td>',
91+
f' {doc_no_newlines}',
92+
' </td>']
93+
elif isinstance(doc, dict):
94+
# We have a bit field with values
95+
line_items = [f'<li>{value}: {desc}</li>' for value, desc in doc['values'].items()]
96+
97+
bit_lines += [f' <td>{idx_formatted}</td>',
98+
' <td>',
99+
f' {doc_no_newlines}',
100+
' <p>Values:</p><ul>']
101+
bit_lines += [f' {item}' for item in line_items]
102+
bit_lines += [' </ul>',
103+
' </td>']
104+
else:
105+
raise ValueError(f'Invalid description format for bit {idx!r} in ISR {uc_name!r}.')
106+
bit_lines += ['</tr>']
107+
108+
for bit in bit_lines:
109+
doc_lines.append(' ' * 4 + bit)
51110
doc_lines += [' </tbody>', '</table>']
52111

53112
for line in doc_lines:

hw/ip/otbn/util/shared/isr.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99

1010
class Isr:
11-
def __init__(self, name: str, address: int,
12-
doc: str, read_only: bool, bits: Dict[int, str]) -> None:
11+
def __init__(self, name: str, address: int, doc: str, read_only: bool,
12+
bits: Dict[str, object]) -> None:
1313
self.name = name
1414
self.address = address
1515
self.doc = doc
@@ -33,11 +33,35 @@ def from_yml(yml: object) -> 'Isr':
3333
pre_bits = yd.get('bits', {})
3434
if not isinstance(pre_bits, dict):
3535
raise ValueError(f'bits field of ISR {name:!r} is not a dict.')
36-
bits = {} # type: Dict[int, str]
37-
for k, v in pre_bits.items():
38-
k_int = check_int(k, 'address of ISR bit')
39-
v_str = check_str(v, f'description of ISR bit {k}')
40-
bits[k_int] = v_str
36+
bits = {} # type: Dict[str, object]
37+
for idx, desc in pre_bits.items():
38+
# An entry in the bits section can either describe a single bit or a bit field.
39+
# A single bit is described as "index: description".
40+
# A bit field is described with a range of bits, a description and optionally a
41+
# list of allowed values.
42+
# A yml example is:
43+
# bits:
44+
# 0: A single bit
45+
# 2-1: A bit field
46+
# 4-3:
47+
# doc: Another bit field
48+
# values:
49+
# 0: Option A
50+
# 1: Option B
51+
52+
# Convert the bit index to string so all cases are handled the same way.
53+
# We do not enforce a strict format for the string contents here, meaning that we allow
54+
# "MSB-5" and similar notations.
55+
if isinstance(idx, int):
56+
idx = str(idx)
57+
elif isinstance(idx, str):
58+
idx = idx
59+
else:
60+
raise ValueError(f'Invalid bit index {idx!r} format in ISR {name!r}.')
61+
62+
# We do not check the description format here. It can be validated when building the
63+
# documentation.
64+
bits[idx] = desc
4165

4266
return Isr(name, address, doc, read_only, bits)
4367

0 commit comments

Comments
 (0)