99import argparse
1010import os
1111import 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
1422sys .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+
2957def 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 :
0 commit comments