1#!/usr/bin/env python3
2
3# Copyright (c) 2019 - 2020 Nordic Semiconductor ASA
4# Copyright (c) 2019 Linaro Limited
5# Copyright (c) 2024 SILA Embedded Solutions GmbH
6# SPDX-License-Identifier: BSD-3-Clause
7
8# This script uses edtlib to generate a header file from a pickled
9# edt file.
10#
11# Note: Do not access private (_-prefixed) identifiers from edtlib here (and
12# also note that edtlib is not meant to expose the dtlib API directly).
13# Instead, think of what API you need, and add it as a public documented API in
14# edtlib. This will keep this script simple.
15
16import argparse
17from collections import defaultdict
18import os
19import pathlib
20import pickle
21import re
22import sys
23from typing import Iterable, NoReturn, Optional
24
25sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'python-devicetree',
26                                'src'))
27
28import edtlib_logger
29from devicetree import edtlib
30
31
32def main():
33    global header_file
34    global flash_area_num
35
36    args = parse_args()
37
38    edtlib_logger.setup_edtlib_logging()
39
40    with open(args.edt_pickle, 'rb') as f:
41        edt = pickle.load(f)
42
43    flash_area_num = 0
44
45    # Create the generated header.
46    with open(args.header_out, "w", encoding="utf-8") as header_file:
47        write_top_comment(edt)
48
49        write_utils()
50
51        sorted_nodes = sorted(edt.nodes, key=lambda node: node.dep_ordinal)
52
53        # populate all z_path_id first so any children references will
54        # work correctly.
55        for node in sorted_nodes:
56            node.z_path_id = node_z_path_id(node)
57
58        # Check to see if we have duplicate "zephyr,memory-region" property values.
59        regions = dict()
60        for node in sorted_nodes:
61            if 'zephyr,memory-region' in node.props:
62                region = node.props['zephyr,memory-region'].val
63                if region in regions:
64                    sys.exit(f"ERROR: Duplicate 'zephyr,memory-region' ({region}) properties "
65                             f"between {regions[region].path} and {node.path}")
66                regions[region] = node
67
68        for node in sorted_nodes:
69            write_node_comment(node)
70
71            out_comment("Node's full path:")
72            out_dt_define(f"{node.z_path_id}_PATH", f'"{escape(node.path)}"')
73
74            out_comment("Node's name with unit-address:")
75            out_dt_define(f"{node.z_path_id}_FULL_NAME",
76                          f'"{escape(node.name)}"')
77            out_dt_define(f"{node.z_path_id}_FULL_NAME_UNQUOTED",
78                          f'{escape(node.name)}')
79            out_dt_define(f"{node.z_path_id}_FULL_NAME_TOKEN",
80                          f'{edtlib.str_as_token(escape(node.name))}')
81            out_dt_define(f"{node.z_path_id}_FULL_NAME_UPPER_TOKEN",
82                          f'{edtlib.str_as_token(escape(node.name)).upper()}')
83
84            if node.parent is not None:
85                out_comment(f"Node parent ({node.parent.path}) identifier:")
86                out_dt_define(f"{node.z_path_id}_PARENT",
87                              f"DT_{node.parent.z_path_id}")
88
89                out_comment(f"Node's index in its parent's list of children:")
90                out_dt_define(f"{node.z_path_id}_CHILD_IDX",
91                              node.parent.child_index(node))
92
93            out_comment("Helpers for dealing with node labels:")
94            out_dt_define(f"{node.z_path_id}_NODELABEL_NUM", len(node.labels))
95            out_dt_define(f"{node.z_path_id}_FOREACH_NODELABEL(fn)",
96                          " ".join(f"fn({nodelabel})" for nodelabel in node.labels))
97            out_dt_define(f"{node.z_path_id}_FOREACH_NODELABEL_VARGS(fn, ...)",
98                          " ".join(f"fn({nodelabel}, __VA_ARGS__)" for nodelabel in node.labels))
99
100            write_parent(node)
101            write_children(node)
102            write_dep_info(node)
103            write_idents_and_existence(node)
104            write_bus(node)
105            write_special_props(node)
106            write_vanilla_props(node)
107
108        write_chosen(edt)
109        write_global_macros(edt)
110
111
112def node_z_path_id(node: edtlib.Node) -> str:
113    # Return the node specific bit of the node's path identifier:
114    #
115    # - the root node's path "/" has path identifier "N"
116    # - "/foo" has "N_S_foo"
117    # - "/foo/bar" has "N_S_foo_S_bar"
118    # - "/foo/bar@123" has "N_S_foo_S_bar_123"
119    #
120    # This is used throughout this file to generate macros related to
121    # the node.
122
123    components = ["N"]
124    if node.parent is not None:
125        components.extend(f"S_{str2ident(component)}" for component in
126                          node.path.split("/")[1:])
127
128    return "_".join(components)
129
130
131def parse_args() -> argparse.Namespace:
132    # Returns parsed command-line arguments
133
134    parser = argparse.ArgumentParser(allow_abbrev=False)
135    parser.add_argument("--header-out", required=True,
136                        help="path to write header to")
137    parser.add_argument("--edt-pickle",
138                        help="path to read pickled edtlib.EDT object from")
139
140    return parser.parse_args()
141
142
143def write_top_comment(edt: edtlib.EDT) -> None:
144    # Writes an overview comment with misc. info at the top of the header and
145    # configuration file
146
147    s = f"""\
148Generated by gen_defines.py
149
150DTS input file:
151  {edt.dts_path}
152
153Directories with bindings:
154  {", ".join(map(relativize, edt.bindings_dirs))}
155
156Node dependency ordering (ordinal and path):
157"""
158
159    for scc in edt.scc_order:
160        if len(scc) > 1:
161            err("cycle in devicetree involving "
162                + ", ".join(node.path for node in scc))
163        s += f"  {scc[0].dep_ordinal:<3} {scc[0].path}\n"
164
165    s += """
166Definitions derived from these nodes in dependency order are next,
167followed by /chosen nodes.
168"""
169
170    out_comment(s, blank_before=False)
171
172
173def write_utils() -> None:
174    # Writes utility macros
175
176    out_comment("Used to remove brackets from around a single argument")
177    out_define("DT_DEBRACKET_INTERNAL(...)", "__VA_ARGS__")
178
179
180def write_node_comment(node: edtlib.Node) -> None:
181    # Writes a comment describing 'node' to the header and configuration file
182
183    s = f"""\
184Devicetree node: {node.path}
185
186Node identifier: DT_{node.z_path_id}
187"""
188
189    if node.matching_compat:
190        if node.binding_path:
191            s += f"""
192Binding (compatible = {node.matching_compat}):
193  {relativize(node.binding_path)}
194"""
195        else:
196            s += f"""
197Binding (compatible = {node.matching_compat}):
198  No yaml (bindings inferred from properties)
199"""
200
201    if node.description:
202        # We used to put descriptions in the generated file, but
203        # devicetree bindings now have pages in the HTML
204        # documentation. Let users who are accustomed to digging
205        # around in the generated file where to find the descriptions
206        # now.
207        #
208        # Keeping them here would mean that the descriptions
209        # themselves couldn't contain C multi-line comments, which is
210        # inconvenient when we want to do things like quote snippets
211        # of .dtsi files within the descriptions, or otherwise
212        # include the string "*/".
213        s += ("\n(Descriptions have moved to the Devicetree Bindings Index\n"
214              "in the documentation.)\n")
215
216    out_comment(s)
217
218
219def relativize(path) -> Optional[str]:
220    # If 'path' is within $ZEPHYR_BASE, returns it relative to $ZEPHYR_BASE,
221    # with a "$ZEPHYR_BASE/..." hint at the start of the string. Otherwise,
222    # returns 'path' unchanged.
223
224    zbase = os.getenv("ZEPHYR_BASE")
225    if zbase is None:
226        return path
227
228    try:
229        return str("$ZEPHYR_BASE" / pathlib.Path(path).relative_to(zbase))
230    except ValueError:
231        # Not within ZEPHYR_BASE
232        return path
233
234
235def write_idents_and_existence(node: edtlib.Node) -> None:
236    # Writes macros related to the node's aliases, labels, etc.,
237    # as well as existence flags.
238
239    # Aliases
240    idents = [f"N_ALIAS_{str2ident(alias)}" for alias in node.aliases]
241    # Instances
242    for compat in node.compats:
243        instance_no = node.edt.compat2nodes[compat].index(node)
244        idents.append(f"N_INST_{instance_no}_{str2ident(compat)}")
245    # Node labels
246    idents.extend(f"N_NODELABEL_{str2ident(label)}" for label in node.labels)
247
248    out_comment("Existence and alternate IDs:")
249    out_dt_define(f"{node.z_path_id}_EXISTS", 1)
250
251    # Only determine maxlen if we have any idents
252    if idents:
253        maxlen = max(len(f"DT_{ident}") for ident in idents)
254    for ident in idents:
255        out_dt_define(ident, f"DT_{node.z_path_id}", width=maxlen)
256
257
258def write_bus(node: edtlib.Node) -> None:
259    # Macros about the node's bus controller, if there is one
260
261    bus = node.bus_node
262    if not bus:
263        return
264
265    out_comment(f"Bus info (controller: '{bus.path}', type: '{node.on_buses}')")
266
267    for one_bus in node.on_buses:
268        out_dt_define(f"{node.z_path_id}_BUS_{str2ident(one_bus)}", 1)
269
270    out_dt_define(f"{node.z_path_id}_BUS", f"DT_{bus.z_path_id}")
271
272
273def write_special_props(node: edtlib.Node) -> None:
274    # Writes required macros for special case properties, when the
275    # data cannot otherwise be obtained from write_vanilla_props()
276    # results
277
278    # Macros that are special to the devicetree specification
279    out_comment("Macros for properties that are special in the specification:")
280    write_regs(node)
281    write_ranges(node)
282    write_interrupts(node)
283    write_compatibles(node)
284    write_status(node)
285
286    # Macros that are special to bindings inherited from Linux, which
287    # we can't capture with the current bindings language.
288    write_pinctrls(node)
289    write_fixed_partitions(node)
290    write_gpio_hogs(node)
291
292
293def write_ranges(node: edtlib.Node) -> None:
294    # ranges property: edtlib knows the right #address-cells and
295    # #size-cells of parent and child, and can therefore pack the
296    # child & parent addresses and sizes correctly
297
298    idx_vals = []
299    path_id = node.z_path_id
300
301    if node.ranges is not None:
302        idx_vals.append((f"{path_id}_RANGES_NUM", len(node.ranges)))
303
304    for i,range in enumerate(node.ranges):
305        idx_vals.append((f"{path_id}_RANGES_IDX_{i}_EXISTS", 1))
306
307        if "pcie" in node.buses:
308            idx_vals.append((f"{path_id}_RANGES_IDX_{i}_VAL_CHILD_BUS_FLAGS_EXISTS", 1))
309            idx_macro = f"{path_id}_RANGES_IDX_{i}_VAL_CHILD_BUS_FLAGS"
310            idx_value = range.child_bus_addr >> ((range.child_bus_cells - 1) * 32)
311            idx_vals.append((idx_macro,
312                             f"{idx_value} /* {hex(idx_value)} */"))
313        if range.child_bus_addr is not None:
314            idx_macro = f"{path_id}_RANGES_IDX_{i}_VAL_CHILD_BUS_ADDRESS"
315            if "pcie" in node.buses:
316                idx_value = range.child_bus_addr & ((1 << (range.child_bus_cells - 1) * 32) - 1)
317            else:
318                idx_value = range.child_bus_addr
319            idx_vals.append((idx_macro,
320                             f"{idx_value} /* {hex(idx_value)} */"))
321        if range.parent_bus_addr is not None:
322            idx_macro = f"{path_id}_RANGES_IDX_{i}_VAL_PARENT_BUS_ADDRESS"
323            idx_vals.append((idx_macro,
324                             f"{range.parent_bus_addr} /* {hex(range.parent_bus_addr)} */"))
325        if range.length is not None:
326            idx_macro = f"{path_id}_RANGES_IDX_{i}_VAL_LENGTH"
327            idx_vals.append((idx_macro,
328                             f"{range.length} /* {hex(range.length)} */"))
329
330    for macro, val in idx_vals:
331        out_dt_define(macro, val)
332
333    out_dt_define(f"{path_id}_FOREACH_RANGE(fn)",
334            " ".join(f"fn(DT_{path_id}, {i})" for i,range in enumerate(node.ranges)))
335
336
337def write_regs(node: edtlib.Node) -> None:
338    # reg property: edtlib knows the right #address-cells and
339    # #size-cells, and can therefore pack the register base addresses
340    # and sizes correctly
341
342    idx_vals = []
343    name_vals = []
344    path_id = node.z_path_id
345
346    if node.regs is not None:
347        idx_vals.append((f"{path_id}_REG_NUM", len(node.regs)))
348
349    for i, reg in enumerate(node.regs):
350        idx_vals.append((f"{path_id}_REG_IDX_{i}_EXISTS", 1))
351        if reg.addr is not None:
352            idx_macro = f"{path_id}_REG_IDX_{i}_VAL_ADDRESS"
353            idx_vals.append((idx_macro,
354                             f"{reg.addr} /* {hex(reg.addr)} */"))
355            if reg.name:
356                name_vals.append((f"{path_id}_REG_NAME_{reg.name}_EXISTS", 1))
357                name_macro = f"{path_id}_REG_NAME_{reg.name}_VAL_ADDRESS"
358                name_vals.append((name_macro, f"DT_{idx_macro}"))
359
360        if reg.size is not None:
361            idx_macro = f"{path_id}_REG_IDX_{i}_VAL_SIZE"
362            idx_vals.append((idx_macro,
363                             f"{reg.size} /* {hex(reg.size)} */"))
364            if reg.name:
365                name_macro = f"{path_id}_REG_NAME_{reg.name}_VAL_SIZE"
366                name_vals.append((name_macro, f"DT_{idx_macro}"))
367
368    for macro, val in idx_vals:
369        out_dt_define(macro, val)
370    for macro, val in name_vals:
371        out_dt_define(macro, val)
372
373
374def write_interrupts(node: edtlib.Node) -> None:
375    # interrupts property: we have some hard-coded logic for interrupt
376    # mapping here.
377    #
378    # TODO: can we push map_arm_gic_irq_type() out of Python and into C with
379    # macro magic in devicetree.h?
380
381    def map_arm_gic_irq_type(irq, irq_num):
382        # Maps ARM GIC IRQ (type)+(index) combo to linear IRQ number
383        if "type" not in irq.data:
384            err(f"Expected binding for {irq.controller!r} to have 'type' in "
385                "interrupt-cells")
386        irq_type = irq.data["type"]
387
388        if irq_type == 0:  # GIC_SPI
389            return irq_num + 32
390        if irq_type == 1:  # GIC_PPI
391            return irq_num + 16
392        err(f"Invalid interrupt type specified for {irq!r}")
393
394    idx_vals = []
395    name_vals = []
396    path_id = node.z_path_id
397
398    if node.interrupts is not None:
399        idx_vals.append((f"{path_id}_IRQ_NUM", len(node.interrupts)))
400
401    for i, irq in enumerate(node.interrupts):
402        for cell_name, cell_value in irq.data.items():
403            name = str2ident(cell_name)
404
405            if cell_name == "irq":
406                if "arm,gic" in irq.controller.compats:
407                    cell_value = map_arm_gic_irq_type(irq, cell_value)
408
409            idx_vals.append((f"{path_id}_IRQ_IDX_{i}_EXISTS", 1))
410            idx_macro = f"{path_id}_IRQ_IDX_{i}_VAL_{name}"
411            idx_vals.append((idx_macro, cell_value))
412            idx_vals.append((idx_macro + "_EXISTS", 1))
413            if irq.name:
414                name_macro = (
415                    f"{path_id}_IRQ_NAME_{str2ident(irq.name)}_VAL_{name}")
416                name_vals.append((name_macro, f"DT_{idx_macro}"))
417                name_vals.append((name_macro + "_EXISTS", 1))
418
419        idx_controller_macro = f"{path_id}_IRQ_IDX_{i}_CONTROLLER"
420        idx_controller_path = f"DT_{irq.controller.z_path_id}"
421        idx_vals.append((idx_controller_macro, idx_controller_path))
422        if irq.name:
423            name_controller_macro = f"{path_id}_IRQ_NAME_{str2ident(irq.name)}_CONTROLLER"
424            name_vals.append((name_controller_macro, f"DT_{idx_controller_macro}"))
425
426    # Interrupt controller info
427    irqs = []
428    while node.interrupts is not None and len(node.interrupts) > 0:
429        irq = node.interrupts[0]
430        irqs.append(irq)
431        if node == irq.controller:
432            break
433        node = irq.controller
434    idx_vals.append((f"{path_id}_IRQ_LEVEL", len(irqs)))
435
436    for macro, val in idx_vals:
437        out_dt_define(macro, val)
438    for macro, val in name_vals:
439        out_dt_define(macro, val)
440
441
442def write_compatibles(node: edtlib.Node) -> None:
443    # Writes a macro for each of the node's compatibles. We don't care
444    # about whether edtlib / Zephyr's binding language recognizes
445    # them. The compatibles the node provides are what is important.
446
447    for i, compat in enumerate(node.compats):
448        out_dt_define(
449            f"{node.z_path_id}_COMPAT_MATCHES_{str2ident(compat)}", 1)
450
451        if node.edt.compat2vendor[compat]:
452            out_dt_define(f"{node.z_path_id}_COMPAT_VENDOR_IDX_{i}_EXISTS", 1)
453            out_dt_define(f"{node.z_path_id}_COMPAT_VENDOR_IDX_{i}",
454                          quote_str(node.edt.compat2vendor[compat]))
455
456        if node.edt.compat2model[compat]:
457            out_dt_define(f"{node.z_path_id}_COMPAT_MODEL_IDX_{i}_EXISTS", 1)
458            out_dt_define(f"{node.z_path_id}_COMPAT_MODEL_IDX_{i}",
459                          quote_str(node.edt.compat2model[compat]))
460
461def write_parent(node: edtlib.Node) -> None:
462    # Visit all parent nodes.
463    def _visit_parent_node(node: edtlib.Node):
464        while node is not None:
465            yield node.parent
466            node = node.parent
467
468    # Writes helper macros for dealing with node's parent.
469    out_dt_define(f"{node.z_path_id}_FOREACH_ANCESTOR(fn)",
470            " ".join(f"fn(DT_{parent.z_path_id})" for parent in
471            _visit_parent_node(node) if parent is not None))
472
473def write_children(node: edtlib.Node) -> None:
474    # Writes helper macros for dealing with node's children.
475
476    out_comment("Helper macros for child nodes of this node.")
477
478    out_dt_define(f"{node.z_path_id}_CHILD_NUM", len(node.children))
479
480    ok_nodes_num = 0
481    for child in node.children.values():
482        if child.status == "okay":
483            ok_nodes_num = ok_nodes_num + 1
484
485    out_dt_define(f"{node.z_path_id}_CHILD_NUM_STATUS_OKAY", ok_nodes_num)
486
487    child_unit_addrs = {}
488    for child in node.children.values():
489        # Provide a way to query child nodes
490        if (addr := child.unit_addr) is not None:
491            child_unit_addrs.setdefault(addr, []).append(child)
492
493    for addr, children in child_unit_addrs.items():
494        if len(children) != 1:
495            # Duplicate unit addresses for different children, skip
496            continue
497
498        out_dt_define(f"{node.z_path_id}_CHILD_UNIT_ADDR_INT_{addr}", f"DT_{children[0].z_path_id}")
499
500    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD(fn)",
501            " ".join(f"fn(DT_{child.z_path_id})" for child in
502                node.children.values()))
503
504    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD_SEP(fn, sep)",
505            " DT_DEBRACKET_INTERNAL sep ".join(f"fn(DT_{child.z_path_id})"
506            for child in node.children.values()))
507
508    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD_VARGS(fn, ...)",
509            " ".join(f"fn(DT_{child.z_path_id}, __VA_ARGS__)"
510            for child in node.children.values()))
511
512    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD_SEP_VARGS(fn, sep, ...)",
513            " DT_DEBRACKET_INTERNAL sep ".join(f"fn(DT_{child.z_path_id}, __VA_ARGS__)"
514            for child in node.children.values()))
515
516    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD_STATUS_OKAY(fn)",
517            " ".join(f"fn(DT_{child.z_path_id})"
518            for child in node.children.values() if child.status == "okay"))
519
520    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD_STATUS_OKAY_SEP(fn, sep)",
521            " DT_DEBRACKET_INTERNAL sep ".join(f"fn(DT_{child.z_path_id})"
522            for child in node.children.values() if child.status == "okay"))
523
524    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD_STATUS_OKAY_VARGS(fn, ...)",
525            " ".join(f"fn(DT_{child.z_path_id}, __VA_ARGS__)"
526            for child in node.children.values() if child.status == "okay"))
527
528    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD_STATUS_OKAY_SEP_VARGS(fn, sep, ...)",
529            " DT_DEBRACKET_INTERNAL sep ".join(f"fn(DT_{child.z_path_id}, __VA_ARGS__)"
530            for child in node.children.values() if child.status == "okay"))
531
532
533def write_status(node: edtlib.Node) -> None:
534    out_dt_define(f"{node.z_path_id}_STATUS_{str2ident(node.status)}", 1)
535
536
537def write_pinctrls(node: edtlib.Node) -> None:
538    # Write special macros for pinctrl-<index> and pinctrl-names properties.
539
540    out_comment("Pin control (pinctrl-<i>, pinctrl-names) properties:")
541
542    out_dt_define(f"{node.z_path_id}_PINCTRL_NUM", len(node.pinctrls))
543
544    if not node.pinctrls:
545        return
546
547    for pc_idx, pinctrl in enumerate(node.pinctrls):
548        out_dt_define(f"{node.z_path_id}_PINCTRL_IDX_{pc_idx}_EXISTS", 1)
549
550        if not pinctrl.name:
551            continue
552
553        name = pinctrl.name_as_token
554
555        # Below we rely on the fact that edtlib ensures the
556        # pinctrl-<pc_idx> properties are contiguous, start from 0,
557        # and contain only phandles.
558        out_dt_define(f"{node.z_path_id}_PINCTRL_IDX_{pc_idx}_TOKEN", name)
559        out_dt_define(f"{node.z_path_id}_PINCTRL_IDX_{pc_idx}_UPPER_TOKEN", name.upper())
560        out_dt_define(f"{node.z_path_id}_PINCTRL_NAME_{name}_EXISTS", 1)
561        out_dt_define(f"{node.z_path_id}_PINCTRL_NAME_{name}_IDX", pc_idx)
562        for idx, ph in enumerate(pinctrl.conf_nodes):
563            out_dt_define(f"{node.z_path_id}_PINCTRL_NAME_{name}_IDX_{idx}_PH",
564                          f"DT_{ph.z_path_id}")
565
566
567def write_fixed_partitions(node: edtlib.Node) -> None:
568    # Macros for child nodes of each fixed-partitions node.
569
570    if not (node.parent and ("fixed-partitions" in node.parent.compats or "fixed-subpartitions" in node.parent.compats)):
571        return
572
573    global flash_area_num
574    out_comment("fixed-partitions identifier:")
575    out_dt_define(f"{node.z_path_id}_PARTITION_ID", flash_area_num)
576    flash_area_num += 1
577
578
579def write_gpio_hogs(node: edtlib.Node) -> None:
580    # Write special macros for gpio-hog node properties.
581
582    macro = f"{node.z_path_id}_GPIO_HOGS"
583    macro2val = {}
584    for i, entry in enumerate(node.gpio_hogs):
585        macro2val.update(controller_and_data_macros(entry, i, macro, ""))
586
587    if macro2val:
588        out_comment("GPIO hog properties:")
589        out_dt_define(f"{macro}_EXISTS", 1)
590        out_dt_define(f"{macro}_NUM", len(node.gpio_hogs))
591        for macro, val in macro2val.items():
592            out_dt_define(macro, val)
593
594
595def write_vanilla_props(node: edtlib.Node) -> None:
596    # Writes macros for any and all properties defined in the
597    # "properties" section of the binding for the node.
598    #
599    # This does generate macros for special properties as well, like
600    # regs, etc. Just let that be rather than bothering to add
601    # never-ending amounts of special case code here to skip special
602    # properties. This function's macros can't conflict with
603    # write_special_props() macros, because they're in different
604    # namespaces. Special cases aren't special enough to break the rules.
605
606    macro2val = {}
607    for prop_name, prop in node.props.items():
608        prop_id = str2ident(prop_name)
609        macro = f"{node.z_path_id}_P_{prop_id}"
610        val = prop2value(prop)
611        if val is not None:
612            # DT_N_<node-id>_P_<prop-id>
613            macro2val[macro] = val
614
615        if prop.spec.type == 'string':
616            macro2val.update(string_macros(macro, prop.val))
617            # DT_N_<node-id>_P_<prop-id>_IDX_0:
618            # DT_N_<node-id>_P_<prop-id>_IDX_0_EXISTS:
619            # Allows treating the string like a degenerate case of a
620            # string-array of length 1.
621            macro2val[f"{macro}_IDX_0"] = quote_str(prop.val)
622            macro2val[f"{macro}_IDX_0_EXISTS"] = 1
623
624        if prop.enum_indices is not None:
625            macro2val.update(enum_macros(prop, macro))
626
627        if "phandle" in prop.type:
628            macro2val.update(phandle_macros(prop, macro))
629        elif "array" in prop.type:
630            macro2val.update(array_macros(prop, macro))
631
632        plen = prop_len(prop)
633        if plen is not None:
634            # DT_N_<node-id>_P_<prop-id>_FOREACH_PROP_ELEM
635            macro2val[f"{macro}_FOREACH_PROP_ELEM(fn)"] = (
636                ' \\\n\t'.join(f'fn(DT_{node.z_path_id}, {prop_id}, {i})'
637                               for i in range(plen)))
638
639            # DT_N_<node-id>_P_<prop-id>_FOREACH_PROP_ELEM_SEP
640            macro2val[f"{macro}_FOREACH_PROP_ELEM_SEP(fn, sep)"] = (
641                ' DT_DEBRACKET_INTERNAL sep \\\n\t'.join(
642                    f'fn(DT_{node.z_path_id}, {prop_id}, {i})'
643                    for i in range(plen)))
644
645            # DT_N_<node-id>_P_<prop-id>_FOREACH_PROP_ELEM_VARGS
646            macro2val[f"{macro}_FOREACH_PROP_ELEM_VARGS(fn, ...)"] = (
647                ' \\\n\t'.join(
648                    f'fn(DT_{node.z_path_id}, {prop_id}, {i}, __VA_ARGS__)'
649                    for i in range(plen)))
650
651            # DT_N_<node-id>_P_<prop-id>_FOREACH_PROP_ELEM_SEP_VARGS
652            macro2val[f"{macro}_FOREACH_PROP_ELEM_SEP_VARGS(fn, sep, ...)"] = (
653                ' DT_DEBRACKET_INTERNAL sep \\\n\t'.join(
654                    f'fn(DT_{node.z_path_id}, {prop_id}, {i}, __VA_ARGS__)'
655                    for i in range(plen)))
656
657            # DT_N_<node-id>_P_<prop-id>_LEN
658            macro2val[f"{macro}_LEN"] = plen
659
660        # DT_N_<node-id>_P_<prop-id>_EXISTS
661        macro2val[f"{macro}_EXISTS"] = 1
662
663    if macro2val:
664        out_comment("Generic property macros:")
665        for macro, val in macro2val.items():
666            out_dt_define(macro, val)
667    else:
668        out_comment("(No generic property macros)")
669
670
671def string_macros(macro: str, val: str):
672    # Returns a dict of macros for a string 'val'.
673    # The 'macro' argument is the N_<node-id>_P_<prop-id>... part.
674
675    as_token = edtlib.str_as_token(val)
676    return {
677        # DT_N_<node-id>_P_<prop-id>_IDX_<i>_STRING_UNQUOTED
678        f"{macro}_STRING_UNQUOTED": escape_unquoted(val),
679        # DT_N_<node-id>_P_<prop-id>_IDX_<i>_STRING_TOKEN
680        f"{macro}_STRING_TOKEN": as_token,
681        # DT_N_<node-id>_P_<prop-id>_IDX_<i>_STRING_UPPER_TOKEN
682        f"{macro}_STRING_UPPER_TOKEN": as_token.upper()}
683
684
685def enum_macros(prop: edtlib.Property, macro: str):
686    # Returns a dict of macros for property 'prop' with a defined enum in their dt-binding.
687    # The 'macro' argument is the N_<node-id>_P_<prop-id> part.
688
689    spec = prop.spec
690    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_ENUM_IDX
691    ret = {f"{macro}_IDX_{i}_ENUM_IDX": index for i, index in enumerate(prop.enum_indices)}
692    val = prop.val_as_tokens if spec.enum_tokenizable else (prop.val if isinstance(prop.val, list) else [prop.val])
693
694    for i, subval in enumerate(val):
695        # make sure the subval is a formated right.
696        if isinstance(subval, str):
697            subval = str2ident(subval)
698        # DT_N_<node-id>_P_<prop-id>_IDX_<i>_EXISTS
699        ret[f"{macro}_IDX_{i}_EXISTS"] = 1
700        # DT_N_<node-id>_P_<prop-id>_IDX_<i>_ENUM_VAL_<val>_EXISTS 1
701        ret[f"{macro}_IDX_{i}_ENUM_VAL_{subval}_EXISTS"] = 1
702        # DT_N_<node-id>_P_<prop-id>_ENUM_VAL_<val>_EXISTS 1
703        ret[f"{macro}_ENUM_VAL_{subval}_EXISTS"] = 1
704
705    return ret
706
707
708def array_macros(prop: edtlib.Property, macro: str):
709    # Returns a dict of macros for array property 'prop'.
710    # The 'macro' argument is the N_<node-id>_P_<prop-id> part.
711
712    ret = {}
713    for i, subval in enumerate(prop.val):
714        # DT_N_<node-id>_P_<prop-id>_IDX_<i>_EXISTS
715        ret[f"{macro}_IDX_{i}_EXISTS"] = 1
716
717        # DT_N_<node-id>_P_<prop-id>_IDX_<i>
718        if isinstance(subval, str):
719            ret[f"{macro}_IDX_{i}"] = quote_str(subval)
720            # DT_N_<node-id>_P_<prop-id>_IDX_<i>_STRING_...
721            ret.update(string_macros(f"{macro}_IDX_{i}", subval))
722        else:
723            ret[f"{macro}_IDX_{i}"] = subval
724
725    return ret
726
727
728def write_dep_info(node: edtlib.Node) -> None:
729    # Write dependency-related information about the node.
730
731    def fmt_dep_list(dep_list):
732        if dep_list:
733            # Sort the list by dependency ordinal for predictability.
734            sorted_list = sorted(dep_list, key=lambda node: node.dep_ordinal)
735            return ("\\\n\t" + " \\\n\t"
736                    .join(f"{n.dep_ordinal}, /* {n.path} */"
737                          for n in sorted_list))
738        else:
739            return "/* nothing */"
740
741    out_comment("Node's hash:")
742    out_dt_define(f"{node.z_path_id}_HASH", node.hash)
743
744    out_comment("Node's dependency ordinal:")
745    out_dt_define(f"{node.z_path_id}_ORD", node.dep_ordinal)
746    out_dt_define(f"{node.z_path_id}_ORD_STR_SORTABLE", f"{node.dep_ordinal:0>5}")
747
748    out_comment("Ordinals for what this node depends on directly:")
749    out_dt_define(f"{node.z_path_id}_REQUIRES_ORDS",
750                  fmt_dep_list(node.depends_on))
751
752    out_comment("Ordinals for what depends directly on this node:")
753    out_dt_define(f"{node.z_path_id}_SUPPORTS_ORDS",
754                  fmt_dep_list(node.required_by))
755
756
757def prop2value(prop: edtlib.Property) -> edtlib.PropertyValType:
758    # Gets the macro value for property 'prop', if there is
759    # a single well-defined C rvalue that it can be represented as.
760    # Returns None if there isn't one.
761
762    if prop.type == "string":
763        return quote_str(prop.val)
764
765    if prop.type == "int":
766        return prop.val
767
768    if prop.type == "boolean":
769        return 1 if prop.val else 0
770
771    if prop.type in ["array", "uint8-array"]:
772        return list2init(f"{val} /* {hex(val)} */" for val in prop.val)
773
774    if prop.type == "string-array":
775        return list2init(quote_str(val) for val in prop.val)
776
777    # phandle, phandles, phandle-array, path, compound: nothing
778    return None
779
780
781def prop_len(prop: edtlib.Property) -> Optional[int]:
782    # Returns the property's length if and only if we should generate
783    # a _LEN macro for the property. Otherwise, returns None.
784    #
785    # The set of types handled here coincides with the allowable types
786    # that can be used with DT_PROP_LEN(). If you change this set,
787    # make sure to update the doxygen string for that macro, and make
788    # sure that DT_FOREACH_PROP_ELEM() works for the new types too.
789    #
790    # This deliberately excludes ranges, dma-ranges, reg and interrupts.
791    # While they have array type, their lengths as arrays are
792    # basically nonsense semantically due to #address-cells and
793    # #size-cells for "reg", #interrupt-cells for "interrupts"
794    # and #address-cells, #size-cells and the #address-cells from the
795    # parent node for "ranges" and "dma-ranges".
796    #
797    # We have special purpose macros for the number of register blocks
798    # / interrupt specifiers. Excluding them from this list means
799    # DT_PROP_LEN(node_id, ...) fails fast at the devicetree.h layer
800    # with a build error. This forces users to switch to the right
801    # macros.
802
803    if prop.type in ["phandle", "string"]:
804        # phandle is treated as a phandles of length 1.
805        # string is treated as a string-array of length 1.
806        return 1
807
808    if (prop.type in ["array", "uint8-array", "string-array",
809                      "phandles", "phandle-array"] and
810                prop.name not in ["ranges", "dma-ranges", "reg", "interrupts"]):
811        return len(prop.val)
812
813    return None
814
815
816def phandle_macros(prop: edtlib.Property, macro: str) -> dict:
817    # Returns a dict of macros for phandle or phandles property 'prop'.
818    #
819    # The 'macro' argument is the N_<node-id>_P_<prop-id> bit.
820    #
821    # These are currently special because we can't serialize their
822    # values without using label properties, which we're trying to get
823    # away from needing in Zephyr. (Label properties are great for
824    # humans, but have drawbacks for code size and boot time.)
825    #
826    # The names look a bit weird to make it easier for devicetree.h
827    # to use the same macros for phandle, phandles, and phandle-array.
828
829    ret = {}
830
831    if prop.type == "phandle":
832        # A phandle is treated as a phandles with fixed length 1.
833        ret[f"{macro}"] = f"DT_{prop.val.z_path_id}"
834        ret[f"{macro}_IDX_0"] = f"DT_{prop.val.z_path_id}"
835        ret[f"{macro}_IDX_0_PH"] = f"DT_{prop.val.z_path_id}"
836        ret[f"{macro}_IDX_0_EXISTS"] = 1
837    elif prop.type == "phandles":
838        for i, node in enumerate(prop.val):
839            ret[f"{macro}_IDX_{i}"] = f"DT_{node.z_path_id}"
840            ret[f"{macro}_IDX_{i}_PH"] = f"DT_{node.z_path_id}"
841            ret[f"{macro}_IDX_{i}_EXISTS"] = 1
842    elif prop.type == "phandle-array":
843        for i, entry in enumerate(prop.val):
844            if entry is None:
845                # Unspecified element. The phandle-array at this index
846                # does not point at a ControllerAndData value, but
847                # subsequent indices in the array may.
848                ret[f"{macro}_IDX_{i}_EXISTS"] = 0
849                continue
850
851            ret.update(controller_and_data_macros(entry, i, macro, prop.name))
852
853    return ret
854
855
856def controller_and_data_macros(entry: edtlib.ControllerAndData, i: int, macro: str, pname: str):
857    # Helper procedure used by phandle_macros().
858    #
859    # Its purpose is to write the "controller" (i.e. label property of
860    # the phandle's node) and associated data macros for a
861    # ControllerAndData.
862
863    ret = {}
864    data = entry.data
865    node = entry.node
866    pname = edtlib.str_as_token(str2ident(pname))
867
868    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_EXISTS
869    ret[f"{macro}_IDX_{i}_EXISTS"] = 1
870    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_PH
871    ret[f"{macro}_IDX_{i}_PH"] = f"DT_{entry.controller.z_path_id}"
872    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_VAL_<VAL>
873    for cell, val in data.items():
874        ret[f"{macro}_IDX_{i}_VAL_{str2ident(cell)}"] = val
875        ret[f"{macro}_IDX_{i}_VAL_{str2ident(cell)}_EXISTS"] = 1
876    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_EXISTS
877    ret[f"{macro}_IDX_{i}_EXISTS"] = 1
878    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_FOREACH_CELL
879    ret[f"{macro}_IDX_{i}_FOREACH_CELL(fn)"] = (
880            ' \\\n\t'.join(f'fn(DT_{node.z_path_id}, {pname}, {i}, {cell})'
881                           for cell in data))
882    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_FOREACH_CELL_SEP
883    ret[f"{macro}_IDX_{i}_FOREACH_CELL_SEP(fn, sep)"] = (
884        ' DT_DEBRACKET_INTERNAL sep \\\n\t'.join(
885            f'fn(DT_{node.z_path_id}, {pname}, {i}, {cell})'
886               for cell in data))
887    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_NUM_CELLS
888    ret[f"{macro}_IDX_{i}_NUM_CELLS"] = len(data)
889
890    if not entry.name:
891        return ret
892
893    name = str2ident(entry.name)
894
895    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_NAME
896    ret[f"{macro}_IDX_{i}_NAME"] = edtlib.str_as_token(name)
897    # DT_N_<node-id>_P_<prop-id>_NAME_<name>_IDX
898    ret[f"{macro}_NAME_{name}_IDX"] = i
899    # DT_N_<node-id>_P_<prop-id>_NAME_<name>_FOREACH_CELL
900    ret[f"{macro}_NAME_{name}_FOREACH_CELL(fn)"] = (
901            ' \\\n\t'.join(f'fn(DT_{node.z_path_id}, {pname}, {name}, {cell})'
902                           for cell in data))
903    # DT_N_<node-id>_P_<prop-id>_NAME_<name>_FOREACH_CELL_SEP
904    ret[f"{macro}_NAME_{name}_FOREACH_CELL_SEP(fn, sep)"] = (
905        ' DT_DEBRACKET_INTERNAL sep \\\n\t'.join(
906            f'fn(DT_{node.z_path_id}, {pname}, {name}, {cell})'
907               for cell in data))
908    # DT_N_<node-id>_P_<prop-id>_NAME_<name>_NUM_CELLS
909    ret[f"{macro}_NAME_{name}_NUM_CELLS"] = len(data)
910    # DT_N_<node-id>_P_<prop-id>_IDX_<i>_NAME
911    ret[f"{macro}_IDX_{i}_NAME"] = quote_str(entry.name)
912    # DT_N_<node-id>_P_<prop-id>_NAME_<NAME>_PH
913    ret[f"{macro}_NAME_{name}_PH"] = f"DT_{entry.controller.z_path_id}"
914    # DT_N_<node-id>_P_<prop-id>_NAME_<NAME>_EXISTS
915    ret[f"{macro}_NAME_{name}_EXISTS"] = 1
916    # DT_N_<node-id>_P_<prop-id>_NAME_<NAME>_VAL_<VAL>
917    for cell, val in data.items():
918        cell_ident = str2ident(cell)
919        ret[f"{macro}_NAME_{name}_VAL_{cell_ident}"] = (
920            f"DT_{macro}_IDX_{i}_VAL_{cell_ident}")
921        ret[f"{macro}_NAME_{name}_VAL_{cell_ident}_EXISTS"] = 1
922
923    return ret
924
925
926def write_chosen(edt: edtlib.EDT):
927    # Tree-wide information such as chosen nodes is printed here.
928
929    out_comment("Chosen nodes\n")
930    chosen = {}
931    for name, node in edt.chosen_nodes.items():
932        chosen[f"DT_CHOSEN_{str2ident(name)}"] = f"DT_{node.z_path_id}"
933        chosen[f"DT_CHOSEN_{str2ident(name)}_EXISTS"] = 1
934    max_len = max(map(len, chosen), default=0)
935    for macro, value in chosen.items():
936        out_define(macro, value, width=max_len)
937
938
939def write_global_macros(edt: edtlib.EDT):
940    # Global or tree-wide information, such as number of instances
941    # with status "okay" for each compatible, is printed here.
942
943
944    out_comment("Macros for iterating over all nodes and enabled nodes")
945    out_dt_define("FOREACH_HELPER(fn)",
946                  " ".join(f"fn(DT_{node.z_path_id})" for node in edt.nodes))
947    out_dt_define("FOREACH_OKAY_HELPER(fn)",
948                  " ".join(f"fn(DT_{node.z_path_id})" for node in edt.nodes
949                           if node.status == "okay"))
950    out_dt_define("FOREACH_VARGS_HELPER(fn, ...)",
951                  " ".join(f"fn(DT_{node.z_path_id}, __VA_ARGS__)" for node in edt.nodes))
952    out_dt_define("FOREACH_OKAY_VARGS_HELPER(fn, ...)",
953                  " ".join(f"fn(DT_{node.z_path_id}, __VA_ARGS__)" for node in edt.nodes
954                           if node.status == "okay"))
955
956    n_okay_macros = {}
957    for_each_macros = {}
958    compat2buses = defaultdict(list)  # just for "okay" nodes
959    for compat, okay_nodes in edt.compat2okay.items():
960        for node in okay_nodes:
961            buses = node.on_buses
962            for bus in buses:
963                if bus is not None and bus not in compat2buses[compat]:
964                    compat2buses[compat].append(bus)
965
966        ident = str2ident(compat)
967        n_okay_macros[f"DT_N_INST_{ident}_NUM_OKAY"] = len(okay_nodes)
968
969        # Helpers for non-INST for-each macros that take node
970        # identifiers as arguments.
971        for_each_macros[f"DT_FOREACH_OKAY_{ident}(fn)"] = (
972            " ".join(f"fn(DT_{node.z_path_id})"
973                     for node in okay_nodes))
974        for_each_macros[f"DT_FOREACH_OKAY_VARGS_{ident}(fn, ...)"] = (
975            " ".join(f"fn(DT_{node.z_path_id}, __VA_ARGS__)"
976                     for node in okay_nodes))
977
978        # Helpers for INST versions of for-each macros, which take
979        # instance numbers. We emit separate helpers for these because
980        # avoiding an intermediate node_id --> instance number
981        # conversion in the preprocessor helps to keep the macro
982        # expansions simpler. That hopefully eases debugging.
983        for_each_macros[f"DT_FOREACH_OKAY_INST_{ident}(fn)"] = (
984            " ".join(f"fn({edt.compat2nodes[compat].index(node)})"
985                     for node in okay_nodes))
986        for_each_macros[f"DT_FOREACH_OKAY_INST_VARGS_{ident}(fn, ...)"] = (
987            " ".join(f"fn({edt.compat2nodes[compat].index(node)}, __VA_ARGS__)"
988                     for node in okay_nodes))
989
990    for compat, nodes in edt.compat2nodes.items():
991        for node in nodes:
992            if compat == "fixed-partitions":
993                for child in node.children.values():
994                    if "label" in child.props:
995                        label = child.props["label"].val
996                        macro = f"COMPAT_{str2ident(compat)}_LABEL_{str2ident(label)}"
997                        val = f"DT_{child.z_path_id}"
998
999                        out_dt_define(macro, val)
1000                        out_dt_define(macro + "_EXISTS", 1)
1001
1002    out_comment('Macros for compatibles with status "okay" nodes\n')
1003    for compat, okay_nodes in edt.compat2okay.items():
1004        if okay_nodes:
1005            out_define(f"DT_COMPAT_HAS_OKAY_{str2ident(compat)}", 1)
1006
1007    out_comment('Macros for status "okay" instances of each compatible\n')
1008    for macro, value in n_okay_macros.items():
1009        out_define(macro, value)
1010    for macro, value in for_each_macros.items():
1011        out_define(macro, value)
1012
1013    out_comment('Bus information for status "okay" nodes of each compatible\n')
1014    for compat, buses in compat2buses.items():
1015        for bus in buses:
1016            out_define(
1017                f"DT_COMPAT_{str2ident(compat)}_BUS_{str2ident(bus)}", 1)
1018
1019
1020def str2ident(s: str) -> str:
1021    # Converts 's' to a form suitable for (part of) an identifier
1022
1023    return re.sub('[-,.@/+]', '_', s.lower())
1024
1025
1026def list2init(l: Iterable[str]) -> str:
1027    # Converts 'l', a Python list (or iterable), to a C array initializer
1028
1029    return "{" + ", ".join(l) + "}"
1030
1031
1032def out_dt_define(
1033    macro: str,
1034    val: str,
1035    width: Optional[int] = None,
1036    deprecation_msg: Optional[str] = None,
1037) -> str:
1038    # Writes "#define DT_<macro> <val>" to the header file
1039    #
1040    # The macro will be left-justified to 'width' characters if that
1041    # is specified, and the value will follow immediately after in
1042    # that case. Otherwise, this function decides how to add
1043    # whitespace between 'macro' and 'val'.
1044    #
1045    # If a 'deprecation_msg' string is passed, the generated identifiers will
1046    # generate a warning if used, via __WARN(<deprecation_msg>)).
1047    #
1048    # Returns the full generated macro for 'macro', with leading "DT_".
1049    ret = f"DT_{macro}"
1050    out_define(ret, val, width=width, deprecation_msg=deprecation_msg)
1051    return ret
1052
1053
1054def out_define(
1055    macro: str,
1056    val: str,
1057    width: Optional[int] = None,
1058    deprecation_msg: Optional[str] = None,
1059) -> None:
1060    # Helper for out_dt_define(). Outputs "#define <macro> <val>",
1061    # adds a deprecation message if given, and allocates whitespace
1062    # unless told not to.
1063
1064    warn = fr' __WARN("{deprecation_msg}")' if deprecation_msg else ""
1065
1066    if width:
1067        s = f"#define {macro.ljust(width)}{warn} {val}"
1068    else:
1069        s = f"#define {macro}{warn} {val}"
1070
1071    print(s, file=header_file)
1072
1073
1074def out_comment(s: str, blank_before=True) -> None:
1075    # Writes 's' as a comment to the header and configuration file. 's' is
1076    # allowed to have multiple lines. blank_before=True adds a blank line
1077    # before the comment.
1078
1079    if blank_before:
1080        print(file=header_file)
1081
1082    if "\n" in s:
1083        # Format multi-line comments like
1084        #
1085        #   /*
1086        #    * first line
1087        #    * second line
1088        #    *
1089        #    * empty line before this line
1090        #    */
1091        res = ["/*"]
1092        for line in s.splitlines():
1093            # Avoid an extra space after '*' for empty lines. They turn red in
1094            # Vim if space error checking is on, which is annoying.
1095            res.append(f" * {line}".rstrip())
1096        res.append(" */")
1097        print("\n".join(res), file=header_file)
1098    else:
1099        # Format single-line comments like
1100        #
1101        #   /* foo bar */
1102        print(f"/* {s} */", file=header_file)
1103
1104ESCAPE_TABLE = str.maketrans(
1105    {
1106        "\n": "\\n",
1107        "\r": "\\r",
1108        "\\": "\\\\",
1109        '"': '\\"',
1110    }
1111)
1112
1113
1114def escape(s: str) -> str:
1115    # Backslash-escapes any double quotes, backslashes, and new lines in 's'
1116
1117    return s.translate(ESCAPE_TABLE)
1118
1119
1120def quote_str(s: str) -> str:
1121    # Puts quotes around 's' and escapes any double quotes and
1122    # backslashes within it
1123
1124    return f'"{escape(s)}"'
1125
1126
1127def escape_unquoted(s: str) -> str:
1128    # C macros cannot contain line breaks, so replace them with spaces.
1129    # Whitespace is used to separate preprocessor tokens, but it does not matter
1130    # which whitespace characters are used, so a line break and a space are
1131    # equivalent with regards to unquoted strings being used as C code.
1132
1133    return s.replace("\r", " ").replace("\n", " ")
1134
1135
1136def err(s: str) -> NoReturn:
1137    raise Exception(s)
1138
1139
1140if __name__ == "__main__":
1141    main()
1142