[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/hw/ip/uart/data/uart.prj.hjson b/hw/ip/uart/data/uart.prj.hjson
index 3050f5e..de0b3b6 100644
--- a/hw/ip/uart/data/uart.prj.hjson
+++ b/hw/ip/uart/data/uart.prj.hjson
@@ -4,9 +4,14 @@
{
name: "uart",
- version: "1.0",
- life_stage: "L2",
- design_stage: "D3",
- verification_stage: "V3",
- notes: "signoff commit id: 92e4298f8c2de268b2420a2c16939cd0784f1bf8"
+ revisions: [
+ {
+ version: "1.0",
+ life_stage: "L2",
+ design_stage: "D3",
+ verification_stage: "V3",
+ commit_id: "92e4298f8c2de268b2420a2c16939cd0784f1bf8",
+ notes: ""
+ }
+ ]
}
diff --git a/site/docs/assets/scss/_markdown.scss b/site/docs/assets/scss/_markdown.scss
index e0f3c48..769d1c1 100644
--- a/site/docs/assets/scss/_markdown.scss
+++ b/site/docs/assets/scss/_markdown.scss
@@ -136,7 +136,10 @@
// Dashboard design
table.hw-project-dashboard {
- td.hw-stage {
- text-align: center;
+ td {
+ vertical-align: middle;
+ &.hw-stage {
+ text-align: center;
+ }
}
}
diff --git a/site/docs/layouts/shortcodes/dashboard.html b/site/docs/layouts/shortcodes/dashboard.html
index af00d2a..92d637a 100644
--- a/site/docs/layouts/shortcodes/dashboard.html
+++ b/site/docs/layouts/shortcodes/dashboard.html
@@ -6,6 +6,7 @@
<th>Life Stage</th>
<th>Design Stage</th>
<th>Verification Stage</th>
+ <th>Commit ID</th>
<th>Notes</th>
</tr>
</thead>
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/',