[topgen] Update LPG logic to account for per-clock group assignments

Signed-off-by: Michael Schaffner <msf@google.com>
diff --git a/hw/ip/alert_handler/data/alert_handler.hjson b/hw/ip/alert_handler/data/alert_handler.hjson
index ac07069..34ac2e3 100644
--- a/hw/ip/alert_handler/data/alert_handler.hjson
+++ b/hw/ip/alert_handler/data/alert_handler.hjson
@@ -63,7 +63,9 @@
             '''
       type: "logic [NAlerts-1:0][NLpgWidth-1:0]",
       default: '''
-'0
+               {
+                 1'b0
+               }
                ''',
       local: "true"
     },
@@ -85,7 +87,11 @@
             defines whether the protocol is synchronous (0) or asynchronous (1).
             '''
       type: "logic [NAlerts-1:0]",
-      default: "'0",
+      default: '''
+               {
+                 '0
+               }
+               '''
       local: "true"
     },
     { name: "N_CLASSES",
diff --git a/hw/ip/alert_handler/data/alert_handler.hjson.tpl b/hw/ip/alert_handler/data/alert_handler.hjson.tpl
index 9a6b35c..493a95c 100644
--- a/hw/ip/alert_handler/data/alert_handler.hjson.tpl
+++ b/hw/ip/alert_handler/data/alert_handler.hjson.tpl
@@ -67,7 +67,15 @@
             '''
       type: "logic [NAlerts-1:0][NLpgWidth-1:0]",
       default: '''
-${lpg_map}
+% if lpg_map:
+               {
+  % for l in list(reversed(lpg_map)):
+                 ${l}${"" if loop.last else ","}
+  % endfor
+               }
+% else:
+               '0
+% endif
                ''',
       local: "true"
     },
@@ -89,7 +97,17 @@
             defines whether the protocol is synchronous (0) or asynchronous (1).
             '''
       type: "logic [NAlerts-1:0]",
-      default: "${async_on}",
+      default: '''
+% if async_on:
+               {
+  % for a in list(reversed(async_on)):
+                 ${a}${"" if loop.last else ","}
+  % endfor
+               }
+% else:
+               '0
+% endif
+               '''
       local: "true"
     },
     { name: "N_CLASSES",
diff --git a/hw/ip/alert_handler/rtl/alert_handler_reg_pkg.sv b/hw/ip/alert_handler/rtl/alert_handler_reg_pkg.sv
index 200ffaf..edc6a4e 100644
--- a/hw/ip/alert_handler/rtl/alert_handler_reg_pkg.sv
+++ b/hw/ip/alert_handler/rtl/alert_handler_reg_pkg.sv
@@ -10,10 +10,14 @@
   parameter int NAlerts = 4;
   parameter int NLpg = 1;
   parameter int NLpgWidth = 1;
-  parameter logic [NAlerts-1:0][NLpgWidth-1:0] LpgMap = '0;
+  parameter logic [NAlerts-1:0][NLpgWidth-1:0] LpgMap = {
+  1'b0
+};
   parameter int EscCntDw = 32;
   parameter int AccuCntDw = 16;
-  parameter logic [NAlerts-1:0] AsyncOn = '0;
+  parameter logic [NAlerts-1:0] AsyncOn = {
+  '0
+};
   parameter int N_CLASSES = 4;
   parameter int N_ESC_SEV = 4;
   parameter int N_PHASES = 4;
diff --git a/hw/ip/alert_handler/util/reg_alert_handler.py b/hw/ip/alert_handler/util/reg_alert_handler.py
index a24cddd..f97d91b 100755
--- a/hw/ip/alert_handler/util/reg_alert_handler.py
+++ b/hw/ip/alert_handler/util/reg_alert_handler.py
@@ -31,19 +31,11 @@
                         type=int,
                         default=16,
                         help='Width of accumulator')
-    parser.add_argument('--async_on',
-                        type=str,
-                        default="'0",
-                        help="""Enables asynchronous signalling between specific
-                        alert RX/TX pairs""")
-    parser.add_argument('--n_lpg',
-                        type=int,
-                        default=1,
-                        help='Number of LPGs')
-    parser.add_argument('--lpg_map',
-                        type=str,
-                        default="'0",
-                        help="""Encodes the alert to LPG mapping""")
+
+    # can currently not be overridden with this script
+    n_lpg = 1
+    lpg_map = ["1'b0"]
+    async_on = ["'0"]
 
     args = parser.parse_args()
 
@@ -55,9 +47,9 @@
         reg_tpl.render(n_alerts=args.n_alerts,
                        esc_cnt_dw=args.esc_cnt_dw,
                        accu_cnt_dw=args.accu_cnt_dw,
-                       async_on=args.async_on,
-                       n_lpg=args.n_lpg,
-                       lpg_map=args.lpg_map,
+                       async_on=async_on,
+                       n_lpg=n_lpg,
+                       lpg_map=lpg_map,
                        n_classes=4))  # leave this constant for now
 
     print(out.getvalue())
diff --git a/hw/top_earlgrey/ip/alert_handler/data/autogen/alert_handler.hjson b/hw/top_earlgrey/ip/alert_handler/data/autogen/alert_handler.hjson
index b4719fa..23e6789 100644
--- a/hw/top_earlgrey/ip/alert_handler/data/autogen/alert_handler.hjson
+++ b/hw/top_earlgrey/ip/alert_handler/data/autogen/alert_handler.hjson
@@ -71,64 +71,66 @@
             '''
       type: "logic [NAlerts-1:0][NLpgWidth-1:0]",
       default: '''
-{5'd19,
-5'd19,
-5'd19,
-5'd19,
-5'd19,
-5'd19,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd18,
-5'd18,
-5'd18,
-5'd18,
-5'd18,
-5'd18,
-5'd17,
-5'd16,
-5'd16,
-5'd16,
-5'd11,
-5'd15,
-5'd15,
-5'd14,
-5'd13,
-5'd13,
-5'd12,
-5'd11,
-5'd10,
-5'd10,
-5'd10,
-5'd10,
-5'd9,
-5'd9,
-5'd9,
-5'd9,
-5'd9,
-5'd9,
-5'd8,
-5'd7,
-5'd0,
-5'd6,
-5'd5,
-5'd4,
-5'd3,
-5'd2,
-5'd1,
-5'd0,
-5'd0,
-5'd0,
-5'd0,
-5'd0}
+               {
+                 5'd19,
+                 5'd19,
+                 5'd19,
+                 5'd19,
+                 5'd19,
+                 5'd19,
+                 5'd17,
+                 5'd17,
+                 5'd17,
+                 5'd17,
+                 5'd17,
+                 5'd17,
+                 5'd17,
+                 5'd17,
+                 5'd17,
+                 5'd17,
+                 5'd18,
+                 5'd18,
+                 5'd18,
+                 5'd18,
+                 5'd18,
+                 5'd18,
+                 5'd17,
+                 5'd16,
+                 5'd16,
+                 5'd16,
+                 5'd11,
+                 5'd15,
+                 5'd15,
+                 5'd14,
+                 5'd13,
+                 5'd13,
+                 5'd12,
+                 5'd11,
+                 5'd10,
+                 5'd10,
+                 5'd10,
+                 5'd10,
+                 5'd9,
+                 5'd9,
+                 5'd9,
+                 5'd9,
+                 5'd9,
+                 5'd9,
+                 5'd8,
+                 5'd7,
+                 5'd0,
+                 5'd6,
+                 5'd5,
+                 5'd4,
+                 5'd3,
+                 5'd2,
+                 5'd1,
+                 5'd0,
+                 5'd0,
+                 5'd0,
+                 5'd0,
+                 5'd0
+               }
                ''',
       local: "true"
     },
@@ -150,7 +152,68 @@
             defines whether the protocol is synchronous (0) or asynchronous (1).
             '''
       type: "logic [NAlerts-1:0]",
-      default: "58'h3ffffffffffffff",
+      default: '''
+               {
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1,
+                 1'b1
+               }
+               '''
       local: "true"
     },
     { name: "N_CLASSES",
diff --git a/hw/top_earlgrey/ip/alert_handler/rtl/autogen/alert_handler_reg_pkg.sv b/hw/top_earlgrey/ip/alert_handler/rtl/autogen/alert_handler_reg_pkg.sv
index 151974d..cd83f75 100644
--- a/hw/top_earlgrey/ip/alert_handler/rtl/autogen/alert_handler_reg_pkg.sv
+++ b/hw/top_earlgrey/ip/alert_handler/rtl/autogen/alert_handler_reg_pkg.sv
@@ -10,67 +10,128 @@
   parameter int NAlerts = 58;
   parameter int NLpg = 20;
   parameter int NLpgWidth = 5;
-  parameter logic [NAlerts-1:0][NLpgWidth-1:0] LpgMap = {5'd19,
-5'd19,
-5'd19,
-5'd19,
-5'd19,
-5'd19,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd17,
-5'd18,
-5'd18,
-5'd18,
-5'd18,
-5'd18,
-5'd18,
-5'd17,
-5'd16,
-5'd16,
-5'd16,
-5'd11,
-5'd15,
-5'd15,
-5'd14,
-5'd13,
-5'd13,
-5'd12,
-5'd11,
-5'd10,
-5'd10,
-5'd10,
-5'd10,
-5'd9,
-5'd9,
-5'd9,
-5'd9,
-5'd9,
-5'd9,
-5'd8,
-5'd7,
-5'd0,
-5'd6,
-5'd5,
-5'd4,
-5'd3,
-5'd2,
-5'd1,
-5'd0,
-5'd0,
-5'd0,
-5'd0,
-5'd0};
+  parameter logic [NAlerts-1:0][NLpgWidth-1:0] LpgMap = {
+  5'd19,
+  5'd19,
+  5'd19,
+  5'd19,
+  5'd19,
+  5'd19,
+  5'd17,
+  5'd17,
+  5'd17,
+  5'd17,
+  5'd17,
+  5'd17,
+  5'd17,
+  5'd17,
+  5'd17,
+  5'd17,
+  5'd18,
+  5'd18,
+  5'd18,
+  5'd18,
+  5'd18,
+  5'd18,
+  5'd17,
+  5'd16,
+  5'd16,
+  5'd16,
+  5'd11,
+  5'd15,
+  5'd15,
+  5'd14,
+  5'd13,
+  5'd13,
+  5'd12,
+  5'd11,
+  5'd10,
+  5'd10,
+  5'd10,
+  5'd10,
+  5'd9,
+  5'd9,
+  5'd9,
+  5'd9,
+  5'd9,
+  5'd9,
+  5'd8,
+  5'd7,
+  5'd0,
+  5'd6,
+  5'd5,
+  5'd4,
+  5'd3,
+  5'd2,
+  5'd1,
+  5'd0,
+  5'd0,
+  5'd0,
+  5'd0,
+  5'd0
+};
   parameter int EscCntDw = 32;
   parameter int AccuCntDw = 16;
-  parameter logic [NAlerts-1:0] AsyncOn = 58'h3ffffffffffffff;
+  parameter logic [NAlerts-1:0] AsyncOn = {
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1,
+  1'b1
+};
   parameter int N_CLASSES = 4;
   parameter int N_ESC_SEV = 4;
   parameter int N_PHASES = 4;
diff --git a/util/topgen.py b/util/topgen.py
index ebabb61..e2cabd3 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -137,12 +137,12 @@
     # default values
     esc_cnt_dw = 32
     accu_cnt_dw = 16
-    async_on = "'0"
+    async_on = []
     # leave this constant
     n_classes = 4
     # low power groups
     n_lpg = 1
-    lpg_map = "'0"
+    lpg_map = []
 
     topname = top["name"]
 
@@ -150,8 +150,9 @@
     n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
     n_lpg = len(top['alert_lpgs'])
     n_lpg_width = n_lpg.bit_length()
-    # format used to print out LPG map indices in binary format
-    lpg_idx_format = str(n_lpg_width) + "'d{:d},\n"
+    # format used to print out indices in binary format
+    async_on_format = "1'b{:01b}"
+    lpg_idx_format = str(n_lpg_width) + "'d{:d}"
 
     # Double check that all these values are greated than 0
     if esc_cnt_dw < 1:
@@ -167,15 +168,12 @@
         n_alerts = 1
         log.warning("no alerts are defined in the system")
     else:
-        async_on = ""
-        lpg_map = ""
+        async_on = []
+        lpg_map = []
         for alert in top['alert']:
             for k in range(alert['width']):
-                async_on = str(alert['async']) + async_on
-                lpg_map = lpg_idx_format.format(alert['lpg_idx']) + lpg_map
-        # convert to hexstring to shorten line length
-        async_on = ("%d'h" % n_alerts) + hex(int(async_on, 2))[2:]
-        lpg_map = '{' + lpg_map[:-2] + '}'
+                async_on.append(async_on_format.format(int(alert['async'])))
+                lpg_map.append(lpg_idx_format.format(int(alert['lpg_idx'])))
 
     log.info("alert handler parameterization:")
     log.info("NAlerts   = %d" % n_alerts)
diff --git a/util/topgen/merge.py b/util/topgen/merge.py
index 56336d6..b28f5c9 100644
--- a/util/topgen/merge.py
+++ b/util/topgen/merge.py
@@ -8,7 +8,7 @@
 from collections import OrderedDict
 from copy import deepcopy
 from math import ceil, log2
-from typing import Dict, List
+from typing import Dict, List, Union, Tuple
 
 from topgen import c, lib
 from .clocks import Clocks
@@ -521,6 +521,26 @@
     return None
 
 
+def _get_clock_group_name(clk: Union[str, OrderedDict], default_ep_grp) -> Tuple[str, str]:
+    """Return the clock group of a particular clock connection
+
+    Checks whether there is a specific clock group associated with this
+    connection and returns its name. If not, this returns the default clock
+    group of the clock end point.
+    """
+    # If the value of a particular connection is a dict,
+    # there are additional attributes to explore
+    if isinstance(clk, str):
+        group_name = default_ep_grp
+        src_name = clk
+    else:
+        assert isinstance(clk, Dict)
+        group_name = clk.get('group', default_ep_grp)
+        src_name = clk['clock']
+
+    return group_name, src_name
+
+
 def extract_clocks(top: OrderedDict):
     '''Add clock exports to top and connections to endpoints
 
@@ -559,15 +579,7 @@
 
         for port, clk in ep['clock_srcs'].items():
 
-            # If the value of a particular connection is a dict,
-            # there are additional attributes to explore
-            if isinstance(clk, str):
-                group_name = ep_grp
-                src_name = clk
-            else:
-                assert isinstance(clk, Dict)
-                group_name = clk.get('group', ep_grp)
-                src_name = clk['clock']
+            group_name, src_name = _get_clock_group_name(clk, ep_grp)
 
             group = clocks.groups[group_name]
 
@@ -767,7 +779,8 @@
     top['alert_lpgs'] = []
     for module in top["module"]:
         # the alert senders are attached to the primary clock of this block,
-        # so let's start by getting that primary clock.
+        # so let's start by getting that primary clock port of an IP (we need
+        # that to look up the clock connection at the top-level).
         block = name_to_block[module['type']]
         block_clock = block.get_primary_clock()
         primary_reset = module['reset_connections'][block_clock.reset]
@@ -776,7 +789,13 @@
         #   1) the clock group of the primary clock
         #   2) the primary reset name
         #   3) the domain of the primary reset
-        clock_group = module['clock_group']
+        #
+        # 1) need to figure out whether the primary clock has a
+        #    specific clock group assignment or not
+        clk = module['clock_srcs'][block_clock.clock]
+        clock_group, _ = _get_clock_group_name(clk, module['clock_group'])
+
+        # 2-3) get reset info
         reset_name = primary_reset['name']
         reset_domain = primary_reset['domain']
 
diff --git a/util/topgen/resets.py b/util/topgen/resets.py
index 1dd1e8f..85d22eb 100644
--- a/util/topgen/resets.py
+++ b/util/topgen/resets.py
@@ -155,7 +155,6 @@
 
         return path
 
-
     def get_lpg_path(self, name: str, domain: Optional[str]) -> str:
         '''Get path to lpg indication signals'''
 
@@ -164,7 +163,7 @@
             raise ValueError(f'Reset {name} is not a reset exported from rstmgr')
 
         if reset.rst_type == 'ext':
-            raise ValueError(f'External reset cannot be associated with an LPG')
+            raise ValueError(f'External reset {name} cannot be associated with an LPG')
 
         path = reset.lpg_path
         if domain:
@@ -172,7 +171,6 @@
 
         return path
 
-
     def get_unused_resets(self, domains: list) -> Dict[str, str]:
         '''Get unused resets'''