[dashboard] Add multiple revisions
As IP grows and updated, it is needed to have multiple versions of IPs
to be managed in the dashboard. For instance, as UART, GPIO, RV_TIMER
were signed off, their versions shall be increased when the logic design
is changed.
This change introduces `revisions` field in the project Hjson file. If
this field is defined, the dashboard prints out new format.
Revised `uart` IP to show the example.
Signed-off-by: Eunchan Kim <eunchan@opentitan.org>
diff --git a/util/dashboard/dashboard_validate.py b/util/dashboard/dashboard_validate.py
index 099453e..e323651 100644
--- a/util/dashboard/dashboard_validate.py
+++ b/util/dashboard/dashboard_validate.py
@@ -38,6 +38,17 @@
'notes': ['s', "random notes"],
}
+entry_required = {
+ 'version': ['s', "module version"],
+ 'life_stage': ['s', "life stage of module"]
+}
+entry_optional = {
+ 'design_stage': ['s', "design stage of module"],
+ 'verification_stage': ['s', "verification stage of module"],
+ 'commit_id': ['s', "Staged commit ID"],
+ 'notes': ['s', "notes"],
+}
+
def validate(regs):
if not 'name' in regs:
@@ -45,8 +56,26 @@
return 1
component = regs['name']
- error = check_keys(regs, field_required, field_optional, component)
+ # If `revisions` is not in the object keys, the tool runs previous
+ # version checker, which has only one version entry.
+ if not "revisions" in regs:
+ error = check_keys(regs, field_required, field_optional, component)
+ if (error > 0):
+ log.error("Component has top level errors. Aborting.")
+ return error
+
+ # Assumes `revisions` field exists in the Hjson object.
+ # It iterates the entries in the `revisions` group.
+ error = 0
+ if not isinstance(regs['revisions'], list):
+ error += 1
+ log.error("`revisions` field should be a list of version entries")
+ return error
+
+ for rev in regs['revisions']:
+ error += check_keys(rev, entry_required, entry_optional, component)
+
if (error > 0):
- log.error("Component has top level errors. Aborting.")
+ log.error("Component has errors in revision field. Aborting.")
return error
diff --git a/util/dashboard/gen_dashboard_entry.py b/util/dashboard/gen_dashboard_entry.py
index d5aff14..4b6b71e 100644
--- a/util/dashboard/gen_dashboard_entry.py
+++ b/util/dashboard/gen_dashboard_entry.py
@@ -50,6 +50,17 @@
else:
log.fail("hjson file import failed\n")
+ # If `revisions` field doesn't exist, the tool assumes the Hjson
+ # as the previous project format, which has only one version entry.
+ if not "revisions" in obj:
+ print_version1_format(obj, outfile)
+ else:
+ print_multiversion_format(obj, outfile)
+ return
+
+
+# Version 1 (single version) format
+def print_version1_format(obj, outfile):
life_stage = obj['life_stage']
life_stage_mapping = convert_stage(obj['life_stage'])
@@ -80,6 +91,10 @@
else:
genout(outfile,
" <td> </td>\n")
+
+ # Empty commit ID
+ genout(outfile, " <td> </td>\n")
+
if 'notes' in obj:
genout(outfile,
" <td>" + mk.markdown(obj['notes']) + "</td>\n")
@@ -88,7 +103,70 @@
" <td> </td>\n")
genout(outfile, " </tr>\n")
# yapf: enable
- return
+
+
+def print_multiversion_format(obj, outfile):
+ # Sort the revision list based on the version field.
+ # TODO: If minor version goes up gte than 10?
+ revisions = sorted(obj["revisions"], key=lambda x: x["version"])
+ outstr = ""
+ for i, rev in enumerate(revisions):
+ outstr += " <tr>\n"
+
+ # If only one entry in `revisions`, no need of `rowspan`.
+ if len(revisions) == 1:
+ outstr += " <td class='fixleft'>"
+ outstr += html.escape(obj['name']) + "</td>\n"
+ # Print out the module name in the first entry only
+ elif i == 0:
+ outstr += " <td class='fixleft' rowspan='{}'>".format(
+ len(revisions))
+ outstr += html.escape(obj['name']) + "</td>\n"
+
+ # Version
+ outstr += " <td class=\"hw-stage\">"
+ outstr += html.escape(rev['version']) + "</td>\n"
+
+ # Life Stage
+ life_stage = rev['life_stage']
+ life_stage_mapping = convert_stage(rev['life_stage'])
+
+ outstr += " <td class=\"hw-stage\"><span class='hw-stage' title='"
+ outstr += html.escape(life_stage_mapping) + "'>"
+ outstr += html.escape(life_stage) + "</span></td>\n"
+
+ if life_stage != 'L0' and 'design_stage' in rev:
+ design_stage_mapping = convert_stage(rev['design_stage'])
+ outstr += " <td class=\"hw-stage\"><span class='hw-stage' title='"
+ outstr += html.escape(design_stage_mapping) + "'>"
+ outstr += html.escape(rev['design_stage']) + "</span></td>\n"
+ else:
+ outstr += " <td> </td>\n"
+
+ if life_stage != 'L0' and 'verification_stage' in rev:
+ verification_stage_mapping = convert_stage(
+ rev['verification_stage'])
+ outstr += " <td class=\"hw-stage\"><span class='hw-stage' title='"
+ outstr += html.escape(verification_stage_mapping) + "'>"
+ outstr += html.escape(rev['verification_stage']) + "</span></td>\n"
+ else:
+ outstr += " <td> </td>\n"
+
+ if 'commit_id' in rev:
+ outstr += " <td class=\"hw-stage\">"
+ outstr += "<a href='https://github.com/lowrisc/opentitan/tree/{}'>{}</a>".format(
+ rev['commit_id'], rev['commit_id'][0:7])
+ outstr += "</td>\n"
+ else:
+ outstr += " <td> </td>\n"
+
+ if 'notes' in rev:
+ outstr += " <td>" + mk.markdown(rev['notes']) + "</td>\n"
+ else:
+ outstr += " <td> </td>\n"
+ outstr += " </tr>\n"
+
+ genout(outfile, outstr)
# Create table of hardware specifications
@@ -102,7 +180,7 @@
if dashboard_validate.validate(obj) == 0:
log.info("Generated dashboard object for " + str(hjson_path))
else:
- log.fail("hjson file import failed")
+ log.error("hjson file import failed")
# create design spec and DV plan references, check for existence below
design_spec_md = re.sub(r'/data/', '/doc/',