[topgen] Generate Software Definitions for Alert Handler
Signed-off-by: Sam Elliott <selliott@lowrisc.org>
diff --git a/util/topgen/c.py b/util/topgen/c.py
index f62eb9f..17ce546 100644
--- a/util/topgen/c.py
+++ b/util/topgen/c.py
@@ -4,7 +4,6 @@
"""This contains a class which is used to help generate `top_{name}.h` and
`top_{name}.h`.
"""
-
from collections import OrderedDict
from mako.template import Template
@@ -137,6 +136,19 @@
self._init_plic_targets()
self._init_plic_mapping()
+ self._init_alert_mapping()
+
+ def modules(self):
+ return [(m["name"],
+ MemoryRegion(self._top_name + Name.from_snake_case(m["name"]),
+ m["base_addr"], m["size"]))
+ for m in self.top["module"]]
+
+ def memories(self):
+ return [(m["name"],
+ MemoryRegion(self._top_name + Name.from_snake_case(m["name"]),
+ m["base_addr"], m["size"]))
+ for m in self.top["memory"]]
def _init_plic_targets(self):
enum = CEnum(self._top_name + Name(["plic", "target"]))
@@ -153,10 +165,11 @@
"""We eventually want to generate a mapping from interrupt id to the
source peripheral.
- In order to do so, we generate two enums, and store the generated names
- in a dictionary that represents the mapping.
+ In order to do so, we generate two enums (one for interrupts, one for
+ sources), and store the generated names in a dictionary that represents
+ the mapping.
- Plic Interrupt ID 0 corresponds to no interrupt, and so no peripheral,
+ PLIC Interrupt ID 0 corresponds to no interrupt, and so no peripheral,
so we encode that in the enum as "unknown".
The interrupts have to be added in order, with "none" first, to ensure
@@ -211,14 +224,55 @@
self.plic_interrupts = interrupts
self.plic_mapping = plic_mapping
- def modules(self):
- return [(m["name"],
- MemoryRegion(self._top_name + Name.from_snake_case(m["name"]),
- m["base_addr"], m["size"]))
- for m in self.top["module"]]
+ def _init_alert_mapping(self):
+ """We eventually want to generate a mapping from alert id to the source
+ peripheral.
- def memories(self):
- return [(m["name"],
- MemoryRegion(self._top_name + Name.from_snake_case(m["name"]),
- m["base_addr"], m["size"]))
- for m in self.top["memory"]]
+ In order to do so, we generate two enums (one for alerts, one for
+ sources), and store the generated names in a dictionary that represents
+ the mapping.
+
+ Alert Handler has no concept of "no alert", unlike the PLIC.
+
+ The alerts have to be added in order, to ensure that they get the
+ correct mapping to their alert id, which is used for addressing the
+ right registers and bits.
+ """
+ sources = CEnum(self._top_name + Name(["alert", "peripheral"]))
+ alerts = CEnum(self._top_name + Name(["alert", "id"]))
+ alert_mapping = CArrayMapping(
+ self._top_name + Name(["alert", "for", "peripheral"]),
+ sources.name)
+
+ # When we generate the `alerts` enum, the only info we have about the
+ # source is the module name. We'll use `source_name_map` to map a short
+ # module name to the full name object used for the enum constant.
+ source_name_map = {}
+
+ for name in self.top["alert_module"]:
+ source_name = sources.add_constant(Name.from_snake_case(name),
+ docstring=name)
+ source_name_map[name] = source_name
+
+ sources.add_last_constant("Final Alert peripheral")
+
+ for alert in self.top["alert"]:
+ if "width" in alert and int(alert["width"]) != 1:
+ for i in range(int(alert["width"])):
+ name = Name.from_snake_case(
+ alert["name"]) + Name([str(i)])
+ irq_id = alerts.add_constant(name, docstring="{} {}".format(
+ alert["name"], i))
+ source_name = source_name_map[alert["module_name"]]
+ alert_mapping.add_entry(irq_id, source_name)
+ else:
+ name = Name.from_snake_case(alert["name"])
+ alert_id = alerts.add_constant(name, docstring=alert["name"])
+ source_name = source_name_map[alert["module_name"]]
+ alert_mapping.add_entry(alert_id, source_name)
+
+ alerts.add_last_constant("The Last Valid Alert ID.")
+
+ self.alert_sources = sources
+ self.alert_alerts = alerts
+ self.alert_mapping = alert_mapping