[util/design] Ensure digests are always placed at the end of a partition

This change makes sure that digests are always placed at the end of a
partition. The RTL invalid default vector is adjusted such that
unallocated space within a partition is accounted for.

This commit also removes the HW_CFG_CONTENT item since it is not needed
anymore.

Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson b/hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson
index ed13db6..9bcf4b5 100644
--- a/hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson
+++ b/hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson
@@ -126,7 +126,7 @@
         {
             name:       "HW_CFG",
             variant:    "Buffered",
-            size:       "208", // in bytes
+            size:       "240", // in bytes
             secret:     "False",
             sw_digest:  "False",
             hw_digest:  "True",
@@ -143,10 +143,6 @@
                     // a value of '0 will be used.
                     inv_default: "<random>",
                 }
-                {
-                    name: "HW_CFG_CONTENT",
-                    size: "168"
-                }
             ],
             desc: '''Hardware configuration bits used to hardwire
             specific hardware functionality. E.g., raw entropy
@@ -217,7 +213,7 @@
         {
             name:       "SECRET2",
             variant:    "Buffered",
-            size:       "120", // in bytes
+            size:       "88", // in bytes
             secret:     "True",
             sw_digest:  "False",
             hw_digest:  "True",
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_pkg.sv.tpl b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_pkg.sv.tpl
index b36fd40..7720220 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_pkg.sv.tpl
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_pkg.sv.tpl
@@ -159,13 +159,16 @@
   } otp_${part["name"].lower()}_t;
   % endif
 % endfor
-
+<% offset =  int(otp_mmap.config["otp"]["depth"]) * int(otp_mmap.config["otp"]["width"]) %>
   // OTP invalid partition default for buffered partitions.
   parameter logic [${int(otp_mmap.config["otp"]["depth"])*int(otp_mmap.config["otp"]["width"])*8-1}:0] PartInvDefault = ${int(otp_mmap.config["otp"]["depth"])*int(otp_mmap.config["otp"]["width"])*8}'({
   % for k, part in enumerate(otp_mmap.config["partitions"][::-1]):
     ${int(part["size"])*8}'({
     % for item in part["items"][::-1]:
-      ${"{}'h{:0X}".format(item["size"] * 8, item["inv_default"])}${("\n    })," if k < len(otp_mmap.config["partitions"])-1 else "\n    })});") if loop.last else ","}
+      % if offset != item['offset'] + item['size']:
+      ${"{}'h{:0X}".format((offset - item['size'] - item['offset']) * 8, 0)}, // unallocated space <% offset = item['offset'] + item['size'] %>
+      % endif
+      ${"{}'h{:0X}".format(item["size"] * 8, item["inv_default"])}${("\n    })," if k < len(otp_mmap.config["partitions"])-1 else "\n    })});") if loop.last else ","}<% offset -= item['size'] %>
     % endfor
   % endfor
 
diff --git a/util/design/lib/OtpMemMap.py b/util/design/lib/OtpMemMap.py
index 0763bd4..a85e712 100644
--- a/util/design/lib/OtpMemMap.py
+++ b/util/design/lib/OtpMemMap.py
@@ -163,9 +163,8 @@
         key_names.append(key["name"])
 
     offset = 0
-    num_part = 0
     part_index = {}
-    for part in config["partitions"]:
+    for j, part in enumerate(config["partitions"]):
         _validate_part(part, offset, key_names)
 
         if part['name'] in part_index:
@@ -173,9 +172,8 @@
             exit(1)
 
         # Loop over items within a partition
-        num_items = 0
         item_index = {}
-        for item in part["items"]:
+        for k, item in enumerate(part["items"]):
             _validate_item(item, offset)
             if item['name'] in item_index:
                 log.error('Item name {} is not unique'.format(item['name']))
@@ -183,8 +181,7 @@
             log.info("> Item {} at offset {} with size {}".format(
                 item["name"], offset, item["size"]))
             offset += check_int(item["size"])
-            item_index[item['name']] = num_items
-            num_items += 1
+            item_index[item['name']] = k
 
         # Place digest at the end of a partition.
         if part["sw_digest"] or part["hw_digest"]:
@@ -192,7 +189,7 @@
             if digest_name in item_index:
                 log.error('Digest name {} is not unique'.format(digest_name))
                 exit(1)
-            item_index[digest_name] = num_items
+            item_index[digest_name] = len(part["items"])
             part["items"].append({
                 "name":
                 digest_name,
@@ -210,6 +207,20 @@
             random_or_hexvalue(part["items"][-1], "inv_default",
                                DIGEST_SIZE * 8)
 
+            # We always place the digest into the last 64bit word
+            # of a partition.
+            canonical_offset = (check_int(part["offset"]) +
+                                check_int(part["size"]) -
+                                DIGEST_SIZE)
+            if offset > canonical_offset:
+                log.error("Not enough space in partitition "
+                          "{} to accommodate a digest. Bytes available "
+                          "= {}, bytes allocated to items = {}".format(
+                              part["name"], part["size"],
+                              offset - part["offset"]))
+                exit(1)
+
+            offset = canonical_offset
             log.info("> Adding digest {} at offset {} with size {}".format(
                 digest_name, offset, DIGEST_SIZE))
             offset += DIGEST_SIZE
@@ -225,10 +236,9 @@
         offset = check_int(part["offset"]) + check_int(part["size"])
 
         part_index.setdefault(part['name'], {
-            'index': num_part,
+            'index': j,
             'items': item_index
         })
-        num_part += 1
 
     if offset > config["otp"]["size"]:
         log.error(
@@ -237,7 +247,7 @@
             offset)
         exit(1)
 
-    log.info("Total number of partitions: {}".format(num_part))
+    log.info("Total number of partitions: {}".format(len(config["partitions"])))
     log.info("Bytes available in OTP: {}".format(config["otp"]["size"]))
     log.info("Bytes required for partitions: {}".format(offset))