gen_defines: play tricks to benefit DT_INST users

Even though it is about to be done for sound technical reasons, a
subsequent patch adding access to all device nodes at the last minute
in the 2.3 release is going to be playing a bit of a fast one on
the Zephyr community, especially users of DT_INST APIs.

In particular, instance numbers are currently allocated only to
enabled nodes, but that will not be true soon: *every* node of a
compatible will be allocated an instance number, even disabled ones.

This is especially unfortunate for drivers and applications that
expect singletons of their compatibles, and use DT_INST(0, ...) to
mean "the one enabled instance of my compatible".

To avoid gratuitous breakage, let's prepare for that by sorting each
edt.compat2nodes sub-list so that enabled instances always come before
disabled ones.

This doesn't break any API guarantees, because there basically *are*
no ordering guarantees, in part precisely to give us the flexibility
to do things like this. And it does help patterns that use instances 0
through N-1, including the important singleton case.

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 a765804..5595f74 100755
--- a/scripts/dts/gen_defines.py
+++ b/scripts/dts/gen_defines.py
@@ -45,6 +45,25 @@
     with open(args.dts_out, "w", encoding="utf-8") as f:
         print(edt.dts_source, file=f)
 
+    # The raw index into edt.compat2nodes[compat] is used for node
+    # instance numbering within a compatible.
+    #
+    # As a way to satisfy people's intuitions about instance numbers,
+    # though, we sort this list so enabled instances come first.
+    #
+    # This might look like a hack, but it keeps drivers and
+    # applications which don't use instance numbers carefully working
+    # as expected, since e.g. instance number 0 is always the
+    # singleton instance if there's just one enabled node of a
+    # particular compatible.
+    #
+    # This doesn't violate any devicetree.h API guarantees about
+    # instance ordering, since we make no promises that instance
+    # numbers are stable across builds.
+    for compat, nodes in edt.compat2nodes.items():
+        edt.compat2nodes[compat] = sorted(
+            nodes, key=lambda node: 0 if node.status == "okay" else 1)
+
     with open(args.header_out, "w", encoding="utf-8") as header_file:
         write_top_comment(edt)