devicetree: add first round of dependency ordinal info

Add the first API functions that directly deal with node dependency
ordinals as determined by edtlib:

- DT_DEP_ORD(node_id): node_id's ordinal
- DT_REQUIRES_DEP_ORDS(node_id): list of dep ordinals for node_id's
  direct dependencies
- DT_SUPPORTS_DEP_ORDS(node_id): list of dep ordinals for nodes
  depending directly on node_id
- DT_INST_ equivalents

This is not meant to be an exhaustive set of macros related to
dependency ordinals; rather, it's a starting out point meant to enable
initial struct device dependency tracking work. We can add more if
needed.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py
index 3895ef4..b522f62 100755
--- a/scripts/dts/gen_defines.py
+++ b/scripts/dts/gen_defines.py
@@ -87,6 +87,7 @@
                               f"DT_{node.parent.z_path_id}")
 
             write_child_functions(node)
+            write_dep_info(node)
             write_idents_and_existence(node)
             write_bus(node)
             write_special_props(node)
@@ -152,7 +153,7 @@
 Directories with bindings:
   {", ".join(map(relativize, edt.bindings_dirs))}
 
-Nodes in dependency order (ordinal and path):
+Node dependency ordering (ordinal and path):
 """
 
     for scc in edt.scc_order:
@@ -175,7 +176,7 @@
     s = f"""\
 Devicetree node: {node.path}
 
-Node's generated path identifier: DT_{node.z_path_id}
+Node identifier: DT_{node.z_path_id}
 """
 
     if node.matching_compat:
@@ -190,18 +191,6 @@
   No yaml (bindings inferred from properties)
 """
 
-    s += f"\nDependency Ordinal: {node.dep_ordinal}\n"
-
-    if node.depends_on:
-        s += "\nRequires:\n"
-        for dep in node.depends_on:
-            s += f"  {dep.dep_ordinal:<3} {dep.path}\n"
-
-    if node.required_by:
-        s += "\nSupports:\n"
-        for req in node.required_by:
-            s += f"  {req.dep_ordinal:<3} {req.path}\n"
-
     if node.description:
         # Indent description by two spaces
         s += "\nDescription:\n" + \
@@ -460,6 +449,31 @@
         out_comment("(No generic property macros)")
 
 
+def write_dep_info(node):
+    # Write dependency-related information about the node.
+
+    def fmt_dep_list(dep_list):
+        if dep_list:
+            # Sort the list by dependency ordinal for predictability.
+            sorted_list = sorted(dep_list, key=lambda node: node.dep_ordinal)
+            return "\\\n\t" + \
+                " \\\n\t".join(f"{n.dep_ordinal}, /* {n.path} */"
+                               for n in sorted_list)
+        else:
+            return "/* nothing */"
+
+    out_comment("Node's dependency ordinal:")
+    out_dt_define(f"{node.z_path_id}_ORD", node.dep_ordinal)
+
+    out_comment("Ordinals for what this node depends on directly:")
+    out_dt_define(f"{node.z_path_id}_REQUIRES_ORDS",
+                  fmt_dep_list(node.depends_on))
+
+    out_comment("Ordinals for what depends directly on this node:")
+    out_dt_define(f"{node.z_path_id}_SUPPORTS_ORDS",
+                  fmt_dep_list(node.required_by))
+
+
 def prop2value(prop):
     # Gets the macro value for property 'prop', if there is
     # a single well-defined C rvalue that it can be represented as.