fix(cot-dt2c): fix various breakages
This change fixes several breakages that were introduced in some build
configurations by the introduction of the cot-dt2c tool.
Some Python environments cannot be managed directly via `pip`, and
invocations of `make`, including `make distclean`, would cause errors
along the lines of:
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
This change has been resolved by ensuring that calls to the cot-dt2c
tool from the build system happen exclusively through Poetry, which
automatically sets up a virtual environment that *can* be modified.
Some environments saw the following error when building platforms where
the cot-dt2c tool was used:
make: *** No rule to make target '<..>/debug/bl2_cot.c', needed
by '<..>/debug/bl2/bl2_cot.o'. Stop.
Additionally, environments with a more recent version of Python saw the
following error:
File "<...>/lib/python3.12/site-packages/cot_dt2c/cot_parser.py",
line 637, in img_to_c
if ifdef:
^^^^^
NameError: name 'ifdef' is not defined
Both of these errors have now been resolved by modifications to the
build system and the cot-dt2c tool to enable preprocessing of the device
tree source file before it is processed by the tool.
As a consequence of this change, the `pydevicetree` library is no longer
vendored into the repository tree, and we instead pull it in via a
dependency in Poetry.
This change also resolves several MyPy warnings and errors related to
missing type hints.
Change-Id: I72b2d01caca3fcb789d3fe2549f318a9c92d77d1
Signed-off-by: Chris Kay <chris.kay@arm.com>
diff --git a/Makefile b/Makefile
index 64bccbc..cb88758 100644
--- a/Makefile
+++ b/Makefile
@@ -121,9 +121,6 @@
SP_MK_GEN ?= ${SPTOOLPATH}/sp_mk_generator.py
SP_DTS_LIST_FRAGMENT ?= ${BUILD_PLAT}/sp_list_fragment.dts
-# Variables for use with Certificate Conversion (cot-dt2c) Tool
-CERTCONVPATH ?= tools/cot_dt2c
-
# Variables for use with ROMLIB
ROMLIBPATH ?= lib/romlib
@@ -1619,7 +1616,6 @@
clean:
$(s)echo " CLEAN"
$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
- $(q)${MAKE} -C ${CERTCONVPATH} clean
ifdef UNIX_MK
$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
else
@@ -1635,7 +1631,6 @@
$(s)echo " REALCLEAN"
$(call SHELL_REMOVE_DIR,${BUILD_BASE})
$(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*)
- $(q)${MAKE} -C ${CERTCONVPATH} clean
ifdef UNIX_MK
$(q)${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
else
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index dff0135..3c4ad64 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -406,7 +406,6 @@
COTDTPATH := fdts/tbbr_cot_descriptors.dtsi
endif
endif
- bl2: cot-dt2c
endif
BL1_SOURCES += ${AUTH_SOURCES} \
@@ -481,16 +480,23 @@
endif
endif
-cot-dt2c:
ifneq ($(COTDTPATH),)
- $(info COT CONVERSION FOR ${COTDTPATH})
- toolpath := $(shell which cot-dt2c)
- ifeq (${toolpath},)
- output := $(shell make -C ./${CERTCONVPATH} install)
- $(info install output ${output})
- toolpath := $(shell which cot-dt2c)
- endif
- output := $(shell ${toolpath} convert-to-c ${COTDTPATH} ${BUILD_PLAT}/bl2_cot.c)
- $(info ${output})
- BL2_SOURCES += ${BUILD_PLAT}/bl2_cot.c
+ cot-dt-defines = IMAGE_BL2 $(BL2_DEFINES) $(PLAT_BL_COMMON_DEFINES)
+ cot-dt-include-dirs = $(BL2_INCLUDE_DIRS) $(PLAT_BL_COMMON_INCLUDE_DIRS)
+
+ cot-dt-cpp-flags = $(cot-dt-defines:%=-D%)
+ cot-dt-cpp-flags += $(cot-dt-include-dirs:%=-I%)
+
+ cot-dt-cpp-flags += $(BL2_CPPFLAGS) $(PLAT_BL_COMMON_CPPFLAGS)
+ cot-dt-cpp-flags += $(CPPFLAGS) $(BL_CPPFLAGS) $(TF_CFLAGS_$(ARCH))
+ cot-dt-cpp-flags += -c -x assembler-with-cpp -E -P -o $@ $<
+
+ $(BUILD_PLAT)/$(COTDTPATH:.dtsi=.dts): $(COTDTPATH) | $$(@D)/
+ $(q)$($(ARCH)-cpp) $(cot-dt-cpp-flags)
+
+ $(BUILD_PLAT)/$(COTDTPATH:.dtsi=.c): $(BUILD_PLAT)/$(COTDTPATH:.dtsi=.dts) | $$(@D)/
+ $(q)poetry -q install
+ $(q)poetry run cot-dt2c convert-to-c $< $@
+
+ BL2_SOURCES += $(BUILD_PLAT)/$(COTDTPATH:.dtsi=.c)
endif
diff --git a/poetry.lock b/poetry.lock
index b465f48..9b98b18 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -217,6 +217,26 @@
test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
[[package]]
+name = "cot-dt2c"
+version = "0.1.0"
+description = "CoT-dt2c Tool is a python script to convert CoT DT file into corresponding C file"
+optional = false
+python-versions = "^3.8"
+files = []
+develop = true
+
+[package.dependencies]
+click = "^8.1.7"
+igraph = "^0.11.6"
+plotly = "^5.23.0"
+pydevicetree = "0.0.13"
+pyparsing = "^3.1.2"
+
+[package.source]
+type = "directory"
+url = "tools/cot_dt2c"
+
+[[package]]
name = "docutils"
version = "0.18.1"
description = "Docutils -- Python Documentation Utilities"
@@ -239,6 +259,66 @@
]
[[package]]
+name = "igraph"
+version = "0.11.6"
+description = "High performance graph data structures and algorithms"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "igraph-0.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3f8b837181e8e87676be3873ce87cc92cc234efd58a2da2f6b4e050db150fcf4"},
+ {file = "igraph-0.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:245c4b7d7657849eff80416f5df4525c8fc44c74a981ee4d44f0ef2612c3bada"},
+ {file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdb7be3d165073c0136295c0808e9edc57ba096cdb26e94086abb04561f7a292"},
+ {file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58974e20df2986a1ae52a16e51ecb387cc0cbeb41c5c0ddff4d373a1bbf1d9c5"},
+ {file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bef14de5e8ab70724a43808b1ed14aaa6fe1002f87e592289027a3827a8f44a"},
+ {file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:86c1e98de2e32d074df8510bf18abfa1f4c5fda4cb28a009985a5d746b0c0125"},
+ {file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ebc5b3d702158abeb2e4d2414374586a2b932e1a07e48352b470600e1733d528"},
+ {file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0efe6d0fb22d3987a800eb3857ed04df9eb4c5dddd0998be05232cb646f1c337"},
+ {file = "igraph-0.11.6-cp38-cp38-win32.whl", hash = "sha256:f4e68b27497b1c8ada2fb2bc35ef3fa7b0d72e84306b3d648d3de240fc618c32"},
+ {file = "igraph-0.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:5665b33dfbfca5f54ce9b4fea6b97903bd0e99fb1b02acf5e57e600bdfa5a355"},
+ {file = "igraph-0.11.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8aabef03d787b519d1075dfc0da4a1109fb113b941334883e3e7947ac30a459e"},
+ {file = "igraph-0.11.6-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1f2cc4a518d99cdf6cae514f85e93e56852bc8c325b3abb96037d1d690b5975f"},
+ {file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e859238be52ab8ccc614d18f9362942bc88ce543afc12548f81ae99b10801d"},
+ {file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d61fbe5e85eb4ae9efe08c461f9bdeedb02a2b5739fbc223d324a71f40a28be2"},
+ {file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6620ba39df29fd42151becf82309b54e57148233c9c3ef890eed62e25eed8a5"},
+ {file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59666589bb3d07f310cda2c5106a8adeeb77c2ef27fecf1c6438b6091f4ca69d"},
+ {file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:8750b6d6caebf199cf7dc41c931f58e330153779707391e30f0a29f02666fb6e"},
+ {file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:967d6f2c30fe94317da15e459374d0fb8ca3e56020412f201ecd07dd5b5352f2"},
+ {file = "igraph-0.11.6-cp39-abi3-win32.whl", hash = "sha256:9744f95a67319eb6cb487ceabf30f5d7940de34bada51f0ba63adbd23e0f94ad"},
+ {file = "igraph-0.11.6-cp39-abi3-win_amd64.whl", hash = "sha256:b80e69eb11faa9c57330a9ffebdde5808966efe1c1f638d4d4827ea04df7aca8"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0329c16092e2ea7930d5f8368666ce7cb704900cc0ea04e4afe9ea1dd46e44af"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21752313f449bd8688e5688e95ea7231cea5e9199c7162535029be0d9af848ac"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea25e136c6c4161f53ff58868b23ff6c845193050ab0e502236d68e5d4174e32"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac84433a03aef15e4b810010b08882b09854a3669450ccf31e392dbe295d2a66"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac697a44e3573169fa2b28c9c37dcf9cf01e0f558b845dd7123860d4c7c8fb89"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bdeae8bf35316eb1fb27bf667dcf5ecf5fcfb0b8f51831bc1b00c39c09c2d73b"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ad7e4aa442935de72554b96733bf6d7f09eac5cee97988a2562bdd3ca173cfa3"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d2818780358a686178866d01568b9df1f29678581734ad7a78882bab54df004"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2352276a20d979f1dea360af4202bb9f0c9a7d2c77f51815c0e625165e82013d"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:687fdab543b507d622fa3043f4227e5b26dc61dcf8ff8c0919fccddcc655f8b8"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57f7f8214cd48c9a4d97f7346a4152ba2d4ac95fb5ee0df4ecf224fce4ba3d14"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2b9cc69ede53f76ffae03b066609aa90184dd68ef15da8c104a97cebb9210838"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:591e1e447c3f0092daf7613a3eaedab83f9a0b0adbaf7702724c5117ded038a5"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ca558eb331bc687bc33e5cd23717e22676e9412f8cda3a31d30c996a0487610d"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf43c30e08debb087c9e3da69aa5cf1b6732968da34d55a614e3421b9a452146"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d38e8d7db72b187d9d2211d0d06b3271fa9f32b04d49d789e2859b5480db0d0"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a318b059051ff78144a1c3cb880f4d933c812bcdb3d833a49cd7168d0427672"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c54027add809b3c5b6685b8deca4ea4763fd000b9ea45c7ee46b7c9d61ff15e"},
+ {file = "igraph-0.11.6.tar.gz", hash = "sha256:837f233256c3319f2a35a6a80d94eafe47b43791ef4c6f9e9871061341ac8e28"},
+]
+
+[package.dependencies]
+texttable = ">=1.6.2"
+
+[package.extras]
+cairo = ["cairocffi (>=1.2.0)"]
+doc = ["Sphinx (>=7.0.0)", "pydoctor (>=23.4.0)", "sphinx-gallery (>=0.14.0)", "sphinx-rtd-theme (>=1.3.0)"]
+matplotlib = ["matplotlib (>=3.6.0)"]
+plotly = ["plotly (>=5.3.0)"]
+plotting = ["cairocffi (>=1.2.0)"]
+test = ["Pillow (>=9)", "cairocffi (>=1.2.0)", "matplotlib (>=3.6.0)", "networkx (>=2.5)", "numpy (>=1.19.0)", "pandas (>=1.1.0)", "plotly (>=5.3.0)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)", "scipy (>=1.5.0)"]
+test-musl = ["cairocffi (>=1.2.0)", "networkx (>=2.5)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)"]
+
+[[package]]
name = "imagesize"
version = "1.4.1"
description = "Getting image size from png/jpeg/jpeg2000/gif file"
@@ -480,6 +560,21 @@
testing = ["flit-core (>=2,<4)", "poetry-core (>=1.0.0)", "pytest (>=7.2.0)", "pytest-rerunfailures", "pytest-xdist", "tomli-w"]
[[package]]
+name = "plotly"
+version = "5.23.0"
+description = "An open-source, interactive data visualization library for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "plotly-5.23.0-py3-none-any.whl", hash = "sha256:76cbe78f75eddc10c56f5a4ee3e7ccaade7c0a57465546f02098c0caed6c2d1a"},
+ {file = "plotly-5.23.0.tar.gz", hash = "sha256:89e57d003a116303a34de6700862391367dd564222ab71f8531df70279fc0193"},
+]
+
+[package.dependencies]
+packaging = "*"
+tenacity = ">=6.2.0"
+
+[[package]]
name = "prettytable"
version = "3.10.2"
description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
@@ -497,6 +592,20 @@
tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"]
[[package]]
+name = "pydevicetree"
+version = "0.0.13"
+description = "A library for parsing Devicetree Source v1"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "pydevicetree-0.0.13-py3-none-any.whl", hash = "sha256:d61c695cec925b90a8b5740053f4b604e51154a9b36e62a2f12ed9ceaf2f8c38"},
+ {file = "pydevicetree-0.0.13.tar.gz", hash = "sha256:5700c05df89bad8fd729c11aa6f764a3323bcb3796f13b32481ae34445cfc1b7"},
+]
+
+[package.dependencies]
+pyparsing = "*"
+
+[[package]]
name = "pyelftools"
version = "0.29"
description = "Library for analyzing ELF files and DWARF debugging information"
@@ -522,6 +631,20 @@
windows-terminal = ["colorama (>=0.4.6)"]
[[package]]
+name = "pyparsing"
+version = "3.1.2"
+description = "pyparsing module - Classes and methods to define and execute parsing grammars"
+optional = false
+python-versions = ">=3.6.8"
+files = [
+ {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"},
+ {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"},
+]
+
+[package.extras]
+diagrams = ["jinja2", "railroad-diagrams"]
+
+[[package]]
name = "pyproject-hooks"
version = "1.1.0"
description = "Wrappers to call pyproject.toml-based build backend hooks."
@@ -883,6 +1006,32 @@
cairosvg = ["cairosvg (>=1.0)"]
[[package]]
+name = "tenacity"
+version = "9.0.0"
+description = "Retry code until it succeeds"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"},
+ {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"},
+]
+
+[package.extras]
+doc = ["reno", "sphinx"]
+test = ["pytest", "tornado (>=4.5)", "typeguard"]
+
+[[package]]
+name = "texttable"
+version = "1.7.0"
+description = "module to create simple ASCII tables"
+optional = false
+python-versions = "*"
+files = [
+ {file = "texttable-1.7.0-py2.py3-none-any.whl", hash = "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917"},
+ {file = "texttable-1.7.0.tar.gz", hash = "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638"},
+]
+
+[[package]]
name = "tlc"
version = "0.9.0"
description = "Transfer List Compiler (TLC) is a Python-based CLI for efficiently handling transfer lists."
@@ -1005,4 +1154,4 @@
[metadata]
lock-version = "2.0"
python-versions = "^3.8"
-content-hash = "8798a2d1efd456c3b68ae464a216f015afaa1bbb653a905148bef17ab8ce278e"
+content-hash = "d893034cad02533bc86fb98c7d93a0eac6a755fea5efd553924e4762ed3f1fdb"
diff --git a/pyproject.toml b/pyproject.toml
index 03d898e..f0b3925 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -14,6 +14,7 @@
[tool.poetry.dependencies]
python = "^3.8"
+cot-dt2c = {path = "tools/cot_dt2c", develop = true}
tlc = {path = "tools/tlc"}
[tool.poetry.group.docs]
diff --git a/tools/cot_dt2c/.gitignore b/tools/cot_dt2c/.gitignore
new file mode 100644
index 0000000..ad4a1f1
--- /dev/null
+++ b/tools/cot_dt2c/.gitignore
@@ -0,0 +1,176 @@
+# Created by https://www.toptal.com/developers/gitignore/api/python
+# Edit at https://www.toptal.com/developers/gitignore?templates=python
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+### Python Patch ###
+# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
+poetry.toml
+
+# ruff
+.ruff_cache/
+
+# LSP config files
+pyrightconfig.json
+
+# End of https://www.toptal.com/developers/gitignore/api/python
diff --git a/tools/cot_dt2c/Makefile b/tools/cot_dt2c/Makefile
deleted file mode 100644
index ad8d9f5..0000000
--- a/tools/cot_dt2c/Makefile
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-
-##* Variables
-SHELL := /usr/bin/env bash
-PYTHON := python
-PYTHONPATH := `pwd`
-
-.PHONY: dist
-dist: clean
- poetry build
-
-#* Installation
-.PHONY: dev-install
-dev-install:
- pip3 install mypy
- pip3 install pytest
- pip install -r requirements.txt
- poetry lock -n && poetry export --without-hashes > requirements.txt
- poetry install -n
- -poetry run mypy --install-types --non-interactive ./
-
-.PHONY: install
-install: dist
- pip install mypy
- pip install pytest
- pip install -r requirements.txt
- pip install dist/*.whl
-
-clean-test: ## remove test and coverage artifacts
- rm -fr .tox/
- rm -f .coverage
- rm -fr htmlcov/
-
-clean-pyc: ## remove Python file artifacts
- find . -name '*.pyc' -exec rm -f {} +
- find . -name '*.pyo' -exec rm -f {} +
- find . -name '*~' -exec rm -f {} +
- find . -name '__pycache__' -exec rm -fr {} +
- find . | grep -E ".pytest_cache" | xargs rm -rf
- find . | grep -E ".mypy_cache" | xargs rm -rf
-
-
-clean-build: ## remove build artifacts
- rm -fr build/
- rm -fr dist/
- rm -fr .eggs/
- find . -name '*.egg-info' -exec rm -fr {} +
- find . -name '*.egg' -exec rm -f {} +
-
-clean-tmp:
- rm -rf ./tmp
-
-#* Cleaning
-.PHONY: clean clean-build clean-pyc clean-test
-clean: uninstall clean-build clean-pyc clean-test clean-tmp ## remove all build, test, coverage and Python artifacts
-
-uninstall:
- pip uninstall -y cot-dt2c
-
-.PHONY: reinstall
-reinstall: clean install
-
-.PHONY: test
-test:
- PYTHONPATH=$(PYTHONPATH) poetry run pytest -c pyproject.toml tests/
diff --git a/tools/cot_dt2c/cot_dt2c/LICENSE b/tools/cot_dt2c/cot_dt2c/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/tools/cot_dt2c/cot_dt2c/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/tools/cot_dt2c/cot_dt2c/cot_parser.py b/tools/cot_dt2c/cot_dt2c/cot_parser.py
index c1d53e2..39e51db 100644
--- a/tools/cot_dt2c/cot_dt2c/cot_parser.py
+++ b/tools/cot_dt2c/cot_dt2c/cot_parser.py
@@ -6,35 +6,15 @@
import sys
import re
-from cot_dt2c.pydevicetree.source.parser import ifdef_stack
-from cot_dt2c.pydevicetree.ast import CellArray, LabelReference
-from cot_dt2c.pydevicetree import *
+from pydevicetree.ast import CellArray, LabelReference
+from pydevicetree import Devicetree, Property, Node
from pathlib import Path
-
-def extractNumber(s):
- for i in s:
- if i.isdigit():
- return (int)(i)
-
- return -1
-
-def removeNumber(s):
- result = ''.join([i for i in s if not i.isdigit()])
- return result
+from typing import List, Optional
class COT:
def __init__(self, inputfile: str, outputfile=None):
- with open(inputfile, 'r') as f:
- contents = f.read()
- pos = contents.find("cot")
- if pos == -1:
- print("not a valid CoT DT file")
- exit(1)
-
- contents = contents[pos:]
-
try:
- self.tree = Devicetree.parseStr(contents)
+ self.tree = Devicetree.parseFile(inputfile)
except:
print("not a valid CoT DT file")
exit(1)
@@ -336,13 +316,10 @@
def format_auth_data_val(self, node:Node, cert:Node):
type_desc = node.name
- if "sp_pkg" in type_desc:
- ptr = removeNumber(type_desc) + "_buf"
- else:
- ptr = type_desc + "_buf"
- len = "(unsigned int)HASH_DER_LEN"
- if "pk" in type_desc:
- len = "(unsigned int)PK_DER_LEN"
+ ptr = type_desc + "_buf"
+ len = "HASH_DER_LEN"
+ if re.search("_pk$", type_desc):
+ len = "PK_DER_LEN"
# edge case
if not self.if_root(cert) and "key_cert" in cert.name:
@@ -351,7 +328,7 @@
return type_desc, ptr, len
- def get_node(self, nodes: list[Node], name: str) -> Node:
+ def get_node(self, nodes: List[Node], name: str) -> Node:
for i in nodes:
if i.name == name:
return i
@@ -458,10 +435,6 @@
def validate_nodes(self) -> bool:
valid = True
- if ifdef_stack:
- print("invalid ifdef macro")
- valid = False
-
certs = self.get_all_certificates()
images = self.get_all_images()
@@ -478,71 +451,16 @@
return valid
- def extract_licence(self, f):
- licence = []
-
- licencereg = re.compile(r'/\*')
- licenceendReg = re.compile(r'\*/')
-
- licencePre = False
-
- for line in f:
- match = licencereg.search(line)
- if match != None:
- licence.append(line)
- licencePre = True
- continue
-
- match = licenceendReg.search(line)
- if match != None:
- licence.append(line)
- licencePre = False
- return licence
-
- if licencePre:
- licence.append(line)
- else:
- return licence
-
- return licence
-
- def licence_to_c(self, licence, f):
- if len(licence) != 0:
- for i in licence:
- f.write(i)
-
- f.write("\n")
- return
-
- def extract_include(self, f):
- include = []
-
- for line in f:
- if "cot" in line:
- return include
-
- if line != "" and "common" not in line and line != "\n":
- include.append(line)
-
- return include
-
- def include_to_c(self, include, f):
+ def include_to_c(self, f):
f.write("#include <stddef.h>\n")
f.write("#include <mbedtls/version.h>\n")
f.write("#include <common/tbbr/cot_def.h>\n")
f.write("#include <drivers/auth/auth_mod.h>\n")
- f.write("\n")
- for i in include:
- f.write(i)
- f.write("\n")
f.write("#include <platform_def.h>\n\n")
return
- def generate_header(self, input, output):
- licence = self.extract_licence(input)
- include = self.extract_include(input)
- self.licence_to_c(licence, output)
- self.include_to_c(include, output)
+ def generate_header(self, output):
+ self.include_to_c(output)
def all_cert_to_c(self, f):
certs = self.get_all_certificates()
@@ -552,17 +470,16 @@
f.write("\n")
def cert_to_c(self, node: Node, f):
- ifdef = node.get_fields("ifdef")
- if ifdef:
- for i in ifdef:
- f.write("{}\n".format(i))
+ node_image_id: int = node.get_field("image-id")
- f.write("static const auth_img_desc_t {} = {{\n".format(node.name))
- f.write("\t.img_id = {},\n".format(node.get_field("image-id").values[0].replace('"', "")))
+ f.write(f"static const auth_img_desc_t {node.name} = {{\n")
+ f.write(f"\t.img_id = {node_image_id},\n")
f.write("\t.img_type = IMG_CERT,\n")
if not self.if_root(node):
- f.write("\t.parent = &{},\n".format(node.get_field("parent").label.name))
+ node_parent: Node = node.get_field("parent")
+
+ f.write(f"\t.parent = &{node_parent.label.name},\n")
else:
f.write("\t.parent = NULL,\n")
@@ -608,13 +525,9 @@
f.write("\t\t\t.type_desc = &{},\n".format(type_desc))
f.write("\t\t\t.data = {\n")
- n = extractNumber(type_desc)
- if "pkg" not in type_desc or n == -1:
- f.write("\t\t\t\t.ptr = (void *){},\n".format(ptr))
- else:
- f.write("\t\t\t\t.ptr = (void *){}[{}],\n".format(ptr, n-1))
+ f.write("\t\t\t\t.ptr = (void *){},\n".format(ptr))
- f.write("\t\t\t\t.len = {}\n".format(data_len))
+ f.write("\t\t\t\t.len = (unsigned int){}\n".format(data_len))
f.write("\t\t\t}\n")
f.write("\t\t}}{}\n".format("," if i != len(auth_data) - 1 else ""))
@@ -623,42 +536,31 @@
f.write("};\n\n")
- if ifdef:
- for i in ifdef:
- f.write("#endif\n")
- f.write("\n")
-
return
def img_to_c(self, node:Node, f):
- ifdef = node.get_fields("ifdef")
- if ifdef:
- for i in ifdef:
- f.write("{}\n".format(i))
+ node_image_id: int = node.get_field("image-id")
+ node_parent: Node = node.get_field("parent")
+ node_hash: Node = node.get_field("hash")
- f.write("static const auth_img_desc_t {} = {{\n".format(node.name))
- f.write("\t.img_id = {},\n".format(node.get_field("image-id").values[0].replace('"', "")))
+ f.write(f"static const auth_img_desc_t {node.name} = {{\n")
+ f.write(f"\t.img_id = {node_image_id},\n")
f.write("\t.img_type = IMG_RAW,\n")
- f.write("\t.parent = &{},\n".format(node.get_field("parent").label.name))
+ f.write(f"\t.parent = &{node_parent.label.name},\n")
f.write("\t.img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) {\n")
f.write("\t\t[0] = {\n")
f.write("\t\t\t.type = AUTH_METHOD_HASH,\n")
f.write("\t\t\t.param.hash = {\n")
f.write("\t\t\t\t.data = &raw_data,\n")
- f.write("\t\t\t\t.hash = &{}\n".format(node.get_field("hash").label.name))
+ f.write(f"\t\t\t\t.hash = &{node_hash.label.name}\n")
f.write("\t\t\t}\n")
f.write("\t\t}\n")
f.write("\t}\n")
f.write("};\n\n")
- if ifdef:
- for i in ifdef:
- f.write("#endif\n")
- f.write("\n")
-
return
def all_img_to_c(self, f):
@@ -672,7 +574,10 @@
nv_ctr = self.get_all_nv_counters()
for nv in nv_ctr:
- f.write("static auth_param_type_desc_t {} = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, {});\n".format(nv.name, nv.get_field("oid")))
+ nv_oid: str = nv.get_field("oid")
+
+ f.write(f"static auth_param_type_desc_t {nv.name} = "\
+ f"AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, \"{nv_oid}\");\n")
f.write("\n")
@@ -682,7 +587,10 @@
pks = self.get_all_pks()
for p in pks:
- f.write("static auth_param_type_desc_t {} = AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, {});\n".format(p.name, p.get_field("oid")))
+ pk_oid: str = p.get_field("oid")
+
+ f.write(f"static auth_param_type_desc_t {p.name} = "\
+ f"AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, \"{pk_oid}\");\n")
f.write("\n")
return
@@ -690,30 +598,17 @@
def buf_to_c(self, f):
certs = self.get_all_certificates()
- buffers = {}
+ buffers = set()
for c in certs:
auth_data = self.get_auth_data(c)
+
for a in auth_data:
type_desc, ptr, data_len = self.format_auth_data_val(a, c)
- if ptr not in buffers:
- buffers[ptr] = c.get_fields("ifdef")
-
- for key, values in buffers.items():
- if values:
- for i in values:
- f.write("{}\n".format(i))
- if "sp_pkg_hash_buf" in key:
- f.write("static unsigned char {}[MAX_SP_IDS][HASH_DER_LEN];\n".format(key))
- elif "pk" in key:
- f.write("static unsigned char {}[PK_DER_LEN];\n".format(key))
- else:
- f.write("static unsigned char {}[HASH_DER_LEN];\n".format(key))
-
- if values:
- for i in values:
- f.write("#endif\n")
+ if not ptr in buffers:
+ f.write(f"static unsigned char {ptr}[{data_len}];\n")
+ buffers.add(ptr)
f.write("\n")
@@ -726,29 +621,18 @@
certs = self.get_all_certificates()
for c in certs:
- ifdef = c.get_fields("ifdef")
- if ifdef:
- for i in ifdef:
- f.write("{}\n".format(i))
-
hash = c.children
for h in hash:
name = h.name
oid = h.get_field("oid")
- if "pk" in name and "pkg" not in name:
- f.write("static auth_param_type_desc_t {} = "\
- "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_PUB_KEY, {});\n".format(name, oid))
- elif "hash" in name:
- f.write("static auth_param_type_desc_t {} = "\
- "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_HASH, {});\n".format(name, oid))
- elif "ctr" in name:
- f.write("static auth_param_type_desc_t {} = "\
- "AUTH_PARAM_TYPE_DESC(AUTH_PARAM_NV_CTR, {});\n".format(name, oid))
+ if re.search("_pk$", name):
+ ty = "AUTH_PARAM_PUB_KEY"
+ elif re.search("_hash$", name):
+ ty = "AUTH_PARAM_HASH"
- if ifdef:
- for i in ifdef:
- f.write("#endif\n")
+ f.write(f"static auth_param_type_desc_t {name} = "\
+ f"AUTH_PARAM_TYPE_DESC({ty}, \"{oid}\");\n")
f.write("\n")
@@ -759,28 +643,14 @@
f.write("static const auth_img_desc_t * const cot_desc[] = {\n")
for i, c in enumerate(certs):
- ifdef = c.get_fields("ifdef")
- if ifdef:
- for i in ifdef:
- f.write("{}\n".format(i))
+ c_image_id: int = c.get_field("image-id")
- f.write("\t[{}] = &{}{}\n".format(c.get_field("image-id").values[0], c.name, ","))
-
- if ifdef:
- for i in ifdef:
- f.write("#endif\n")
+ f.write(f"\t[{c_image_id}] = &{c.name},\n")
for i, c in enumerate(images):
- ifdef = c.get_fields("ifdef")
- if ifdef:
- for i in ifdef:
- f.write("{}\n".format(i))
+ c_image_id: int = c.get_field("image-id")
- f.write("\t[{}] = &{}{}\n".format(c.get_field("image-id").values[0], c.name, "," if i != len(images) - 1 else ""))
-
- if ifdef:
- for i in ifdef:
- f.write("#endif\n")
+ f.write(f"\t[{c_image_id}] = &{c.name},\n")
f.write("};\n\n")
f.write("REGISTER_COT(cot_desc);\n")
@@ -789,16 +659,15 @@
def generate_c_file(self):
filename = Path(self.output)
filename.parent.mkdir(exist_ok=True, parents=True)
- output = open(self.output, 'w+')
- input = open(self.input, "r")
- self.generate_header(input, output)
- self.buf_to_c(output)
- self.param_to_c(output)
- self.nv_to_c(output)
- self.pk_to_c(output)
- self.all_cert_to_c(output)
- self.all_img_to_c(output)
- self.cot_to_c(output)
+ with open(self.output, 'w+') as output:
+ self.generate_header(output)
+ self.buf_to_c(output)
+ self.param_to_c(output)
+ self.nv_to_c(output)
+ self.pk_to_c(output)
+ self.all_cert_to_c(output)
+ self.all_img_to_c(output)
+ self.cot_to_c(output)
return
diff --git a/tools/cot_dt2c/cot_dt2c/dt_validator.py b/tools/cot_dt2c/cot_dt2c/dt_validator.py
index 65e8ca2..ade037c 100644
--- a/tools/cot_dt2c/cot_dt2c/dt_validator.py
+++ b/tools/cot_dt2c/cot_dt2c/dt_validator.py
@@ -7,7 +7,7 @@
import sys
from os import path, walk, mkdir
import subprocess
-from cot_dt2c.pydevicetree import *
+from pydevicetree import Devicetree
class bcolors:
HEADER = '\033[95m'
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py
deleted file mode 100644
index 49595a7..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-from cot_dt2c.pydevicetree.ast import Devicetree, Node, Property, Directive, CellArray, LabelReference
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py
deleted file mode 100644
index f30d897..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-from cot_dt2c.pydevicetree.ast.directive import Directive
-from cot_dt2c.pydevicetree.ast.node import Node, NodeReference, Devicetree
-from cot_dt2c.pydevicetree.ast.property import PropertyValues, Bytestring, CellArray, StringList, Property, \
- RegArray, OneString
-from cot_dt2c.pydevicetree.ast.reference import Label, Path, Reference, LabelReference, PathReference
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py
deleted file mode 100644
index fdd6f0e..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/directive.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-from typing import Any
-
-from cot_dt2c.pydevicetree.ast.helpers import formatLevel, wrapStrings
-
-class Directive:
- """Represents a Devicetree directive
-
- Directives in Devicetree source are statements of the form
-
- /directive-name/ [option1 [option2 [...]]];
-
- Common directive examples include:
-
- /dts-v1/;
- /include/ "overlay.dtsi";
- /delete-node/ &uart0;
- /delete-property/ status;
-
- Their semantic meaning depends on the directive name, their location in the Devicetree,
- and their options.
- """
- def __init__(self, directive: str, option: Any = None):
- """Create a directive object"""
- self.directive = directive
- self.option = option
-
- def __repr__(self) -> str:
- return "<Directive %s>" % self.directive
-
- def __str__(self) -> str:
- return self.to_dts()
-
- def to_dts(self, level: int = 0) -> str:
- """Format the Directive in Devicetree Source format"""
- if isinstance(self.option, list):
- return formatLevel(level, "%s %s;\n" % (self.directive,
- wrapStrings(self.option)))
- if isinstance(self.option, str):
- if self.directive == "/include/":
- return formatLevel(level, "%s \"%s\"\n" % (self.directive, self.option))
- return formatLevel(level, "%s \"%s\";\n" % (self.directive, self.option))
- return formatLevel(level, "%s;\n" % self.directive)
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py
deleted file mode 100644
index 30c54dc..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/helpers.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-from typing import List, Any
-
-from cot_dt2c.pydevicetree.ast.reference import Reference
-
-def formatLevel(level: int, s: str) -> str:
- """Helper to indent a string with a number of tabs"""
- return "\t" * level + s
-
-def wrapStrings(values: List[Any], formatHex: bool = False) -> List[Any]:
- """Helper to wrap strings in quotes where appropriate"""
- wrapped = []
- for v in values:
- if isinstance(v, Reference):
- wrapped.append(v.to_dts())
- elif isinstance(v, str):
- wrapped.append("\"%s\"" % v)
- elif isinstance(v, int):
- if formatHex:
- wrapped.append("0x%x" % v)
- else:
- wrapped.append(str(v))
- else:
- wrapped.append(str(v))
- return wrapped
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py
deleted file mode 100644
index d203af8..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/node.py
+++ /dev/null
@@ -1,514 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-import re
-import os
-from typing import List, Union, Optional, Iterable, Callable, Any, cast, Pattern
-
-from cot_dt2c.pydevicetree.ast.helpers import formatLevel
-from cot_dt2c.pydevicetree.ast.property import Property, PropertyValues, RegArray, RangeArray
-from cot_dt2c.pydevicetree.ast.directive import Directive
-from cot_dt2c.pydevicetree.ast.reference import Label, Path, Reference, LabelReference, PathReference
-
-# Type signature for elements passed to Devicetree constructor
-ElementList = Iterable[Union['Node', Property, Directive]]
-
-# Callback type signatures for Devicetree.match() and Devicetree.chosen()
-MatchFunc = Callable[['Node'], bool]
-MatchCallback = Optional[Callable[['Node'], None]]
-ChosenCallback = Optional[Callable[[PropertyValues], None]]
-
-class Node:
- """Represents a Devicetree Node
-
- A Devicetree Node generally takes the form
-
- [label:] node-name@unit-address {
- [directives]
- [properties]
- [child nodes]
- };
-
- The structure formed by creating trees of Nodes is the bulk of any Devicetree. As the naming
- system implies, then, each node roughly corresponds to some conceptual device, subsystem of
- devices, bus, etc.
-
- Devices can be referenced by label or by path, and are generally uniquely identified by a
- collection of string identifiers assigned to the "compatible" property.
-
- For instance, a UART device might look like
-
- uart0: uart@10013000 {
- compatible = "sifive,uart0";
- reg = <0x10013000 0x1000>;
- reg-names = "control";
- interrupt-parent = <&plic>;
- interrupts = <3>;
- clocks = <&busclk>;
- status = "okay";
- };
-
- This node can be identified in the following ways:
-
- - By label: uart0
- - By path: /path/to/uart@10013000
- - By name: uart@10013000 (for example when referenced in a /delete-node/ directive)
- """
- # pylint: disable=too-many-arguments
- def __init__(self, name: str, label: Optional[str], address: Optional[int],
- properties: List[Property], directives: List[Directive],
- children: List['Node']):
- """Initializes a Devicetree Node
-
- Also evaluates the /delete-node/ and /delete-property/ directives found in the node
- and deletes the respective nodes and properties.
- """
- self.name = name
- self.parent = None # type: Optional['Node']
-
- self.label = label
- self.address = address
- self.properties = properties
- self.directives = directives
- self.children = children
- self.ifdef = []
-
- for d in self.directives:
- if d.directive == "/delete-node/":
- if isinstance(d.option, LabelReference):
- node = self.get_by_reference(d.option)
- elif isinstance(d.option, str):
- node = self.__get_child_by_handle(d.option)
- if node:
- self.remove_child(node)
- elif d.directive == "/delete-property/":
- # pylint: disable=cell-var-from-loop
- properties = list(filter(lambda p: p.name == d.option, self.properties))
- if properties:
- del self.properties[self.properties.index(properties[0])]
-
- def __repr__(self) -> str:
- if self.address:
- return "<Node %s@%x>" % (self.name, self.address)
- return "<Node %s>" % self.name
-
- def __str__(self) -> str:
- return self.to_dts()
-
- def __eq__(self, other) -> bool:
- return self.name == other.name and self.address == other.address
-
- def __hash__(self):
- return hash((self.name, self.address))
-
- @staticmethod
- def from_dts(source: str) -> 'Node':
- """Create a node from Devicetree Source"""
- # pylint: disable=import-outside-toplevel,cyclic-import
- from pydevicetree.source import parseNode
- return parseNode(source)
-
- def add_child(self, node: 'Node', merge: bool = True):
- """Add a child node and merge it into the tree"""
- node.parent = self
- self.children.append(node)
- if merge:
- self.merge_tree()
-
- def to_dts(self, level: int = 0) -> str:
- """Format the subtree starting at the node as Devicetree Source"""
- out = ""
- if isinstance(self.address, int) and self.label:
- out += formatLevel(level,
- "%s: %s@%x {\n" % (self.label, self.name, self.address))
- elif isinstance(self.address, int):
- out += formatLevel(level, "%s@%x {\n" % (self.name, self.address))
- elif self.label:
- out += formatLevel(level, "%s: %s {\n" % (self.label, self.name))
- elif self.name != "":
- out += formatLevel(level, "%s {\n" % self.name)
-
- for d in self.directives:
- out += d.to_dts(level + 1)
- for p in self.properties:
- out += p.to_dts(level + 1)
- for c in self.children:
- out += c.to_dts(level + 1)
-
- if self.name != "":
- out += formatLevel(level, "};\n")
-
- return out
-
- def merge_tree(self):
- """Recursively merge child nodes into a single tree
-
- Parsed Devicetrees can describe the same tree multiple times, adding nodes and properties
- each time. After parsing, this method is called to recursively merge the tree.
- """
- partitioned_children = []
- for n in self.children:
- partitioned_children.append([e for e in self.children if e == n])
-
- new_children = []
- for part in partitioned_children:
- first = part[0]
- rest = part[1:]
- if first not in new_children:
- for n in rest:
- first.merge(n)
- new_children.append(first)
-
- self.children = new_children
-
- for n in self.children:
- n.parent = self
- n.merge_tree()
-
- def merge(self, other: 'Node'):
- """Merge the contents of a node into this node.
-
- Used by Node.merge_trees()
- """
- if not self.label and other.label:
- self.label = other.label
- self.properties += other.properties
- self.directives += other.directives
- self.children += other.children
- self.ifdef += other.ifdef
-
- def get_path(self, includeAddress: bool = True) -> str:
- """Get the path of a node (ex. /cpus/cpu@0)"""
- if self.name == "/":
- return ""
- if self.parent is None:
- return "/" + self.name
- if isinstance(self.address, int) and includeAddress:
- return self.parent.get_path() + "/" + self.name + "@" + ("%x" % self.address)
- return self.parent.get_path() + "/" + self.name
-
- def get_by_reference(self, reference: Reference) -> Optional['Node']:
- """Get a node from the subtree by reference (ex. &label, &{/path/to/node})"""
- if isinstance(reference, LabelReference):
- return self.get_by_label(reference.label)
- if isinstance(reference, PathReference):
- return self.get_by_path(reference.path)
-
- return None
-
- def get_by_label(self, label: Union[Label, str]) -> Optional['Node']:
- """Get a node from the subtree by label"""
- matching_nodes = list(filter(lambda n: n.label == label, self.child_nodes()))
- if len(matching_nodes) != 0:
- return matching_nodes[0]
- return None
-
- def __get_child_by_handle(self, handle: str) -> Optional['Node']:
- """Get a child node by name or name and unit address"""
- if '@' in handle:
- name, addr_s = handle.split('@')
- address = int(addr_s, base=16)
- nodes = list(filter(lambda n: n.name == name and n.address == address, self.children))
- else:
- name = handle
- nodes = list(filter(lambda n: n.name == name, self.children))
-
- if not nodes:
- return None
- if len(nodes) > 1:
- raise Exception("Handle %s is ambiguous!" % handle)
- return nodes[0]
-
- def get_by_path(self, path: Union[Path, str]) -> Optional['Node']:
- """Get a node in the subtree by path"""
- matching_nodes = list(filter(lambda n: path == n.get_path(includeAddress=True), \
- self.child_nodes()))
- if len(matching_nodes) != 0:
- return matching_nodes[0]
-
- matching_nodes = list(filter(lambda n: path == n.get_path(includeAddress=False), \
- self.child_nodes()))
- if len(matching_nodes) != 0:
- return matching_nodes[0]
- return None
-
- def filter(self, matchFunc: MatchFunc, cbFunc: MatchCallback = None) -> List['Node']:
- """Filter all child nodes by matchFunc
-
- If cbFunc is provided, this method will iterate over the Nodes selected by matchFunc
- and call cbFunc on each Node
-
- Returns a list of all matching Nodes
- """
- nodes = list(filter(matchFunc, self.child_nodes()))
-
- if cbFunc is not None:
- for n in nodes:
- cbFunc(n)
-
- return nodes
-
- def match(self, compatible: Pattern, func: MatchCallback = None) -> List['Node']:
- """Get a node from the subtree by compatible string
-
- Accepts a regular expression to match one of the strings in the compatible property.
- """
- regex = re.compile(compatible)
-
- def match_compat(node: Node) -> bool:
- compatibles = node.get_fields("compatible")
- if compatibles is not None:
- return any(regex.match(c) for c in compatibles)
- return False
-
- return self.filter(match_compat, func)
-
- def child_nodes(self) -> Iterable['Node']:
- """Get an iterable over all the nodes in the subtree"""
- for n in self.children:
- yield n
- for m in n.child_nodes():
- yield m
-
- def remove_child(self, node):
- """Remove a child node"""
- del self.children[self.children.index(node)]
-
- def get_fields(self, field_name: str) -> Optional[PropertyValues]:
- """Get all the values of a property"""
- for p in self.properties:
- if p.name == field_name:
- return p.values
- return None
-
- def has_field(self, field_name: str) -> bool:
- for p in self.properties:
- if p.name == field_name:
- return True
- return False
-
- def get_field(self, field_name: str) -> Any:
- """Get the first value of a property"""
- fields = self.get_fields(field_name)
- if fields is not None:
- if len(cast(PropertyValues, fields)) != 0:
- return fields[0]
- return None
-
- def get_reg(self) -> Optional[RegArray]:
- """If the node defines a `reg` property, return a RegArray for easier querying"""
- reg = self.get_fields("reg")
- reg_names = self.get_fields("reg-names")
- if reg is not None:
- if reg_names is not None:
- return RegArray(reg.values, self.address_cells(), self.size_cells(),
- reg_names.values)
- return RegArray(reg.values, self.address_cells(), self.size_cells())
- return None
-
- def get_ranges(self) -> Optional[RangeArray]:
- """If the node defines a `ranges` property, return a RangeArray for easier querying"""
- ranges = self.get_fields("ranges")
- child_address_cells = self.get_field("#address-cells")
- parent_address_cells = self.address_cells()
- size_cells = self.get_field("#size-cells")
- if ranges is not None:
- return RangeArray(ranges.values, child_address_cells, parent_address_cells, size_cells)
- return None
-
- def address_cells(self):
- """Get the number of address cells
-
- The #address-cells property is defined by the parent of a node and describes how addresses
- are encoded in cell arrays. If no property is defined, the default value is 2.
- """
- if self.parent is not None:
- cells = self.parent.get_field("#address-cells")
- if cells is not None:
- return cells
- return 2
- return 2
-
- def size_cells(self):
- """Get the number of size cells
-
- The #size-cells property is defined by the parent of a node and describes how addresses
- are encoded in cell arrays. If no property is defined, the default value is 1.
- """
- if self.parent is not None:
- cells = self.parent.get_field("#size-cells")
- if cells is not None:
- return cells
- return 1
- return 1
-
-class NodeReference(Node):
- """A NodeReference is used to extend the definition of a previously-defined Node
-
- NodeReferences are commonly used by Devicetree "overlays" to extend the properties of a node
- or add child devices, such as to a bus like I2C.
- """
- def __init__(self, reference: Reference, properties: List[Property],
- directives: List[Directive], children: List[Node]):
- """Instantiate a Node identified by reference to another node"""
- self.reference = reference
- Node.__init__(self, label=None, name="", address=None, properties=properties,
- directives=directives, children=children)
-
- def __repr__(self) -> str:
- return "<NodeReference %s>" % self.reference.to_dts()
-
- def resolve_reference(self, tree: 'Devicetree') -> Node:
- """Given the full tree, get the node being referenced"""
- node = tree.get_by_reference(self.reference)
- if node is None:
- raise Exception("Node reference %s cannot be resolved" % self.reference.to_dts())
- return cast(Node, node)
-
- def to_dts(self, level: int = 0) -> str:
- out = formatLevel(level, self.reference.to_dts() + " {\n")
-
- for d in self.directives:
- out += d.to_dts(level + 1)
- for p in self.properties:
- out += p.to_dts(level + 1)
- for c in self.children:
- out += c.to_dts(level + 1)
-
- out += formatLevel(level, "};\n")
-
- return out
-
-
-class Devicetree(Node):
- """A Devicetree object describes the full Devicetree tree
-
- This class encapsulates both the tree itself (starting at the root node /) and any Directives
- or nodes which exist at the top level of the Devicetree Source files.
-
- Devicetree Source files can be parsed by calling Devicetree.parseFile().
- """
- def __init__(self, elements: ElementList):
- """Instantiate a Devicetree with the list of parsed elements
-
- Resolves all reference nodes and merges the tree to combine all identical nodes.
- """
- properties = [] # type: List[Property]
- directives = [] # type: List[Directive]
- children = [] # type: List[Node]
-
- for e in elements:
- if isinstance(e, Node):
- children.append(cast(Node, e))
- elif isinstance(e, Property):
- properties.append(cast(Property, e))
- elif isinstance(e, Directive):
- directives.append(cast(Directive, e))
-
- Node.__init__(self, label=None, name="", address=None,
- properties=properties, directives=directives, children=children)
-
- for node in self.children:
- node.parent = self
-
- reference_nodes = self.filter(lambda n: isinstance(n, NodeReference))
- for refnode in reference_nodes:
- refnode = cast(NodeReference, refnode)
-
- node = refnode.resolve_reference(self)
-
- if refnode.parent:
- cast(Node, refnode.parent).remove_child(refnode)
-
- node.properties += refnode.properties
- node.directives += refnode.directives
- node.children += refnode.children
-
- self.merge_tree()
-
- def __repr__(self) -> str:
- name = self.root().get_field("compatible")
- return "<Devicetree %s>" % name
-
- def to_dts(self, level: int = 0) -> str:
- """Convert the tree back to Devicetree Source"""
- out = ""
-
- for d in self.directives:
- out += d.to_dts()
- for p in self.properties:
- out += p.to_dts()
- for c in self.children:
- out += c.to_dts()
-
- return out
-
- def get_by_path(self, path: Union[Path, str]) -> Optional[Node]:
- """Get a node in the tree by path (ex. /cpus/cpu@0)"""
-
- # Find and replace all aliases in the path
- aliases = self.aliases()
- if aliases:
- for prop in aliases.properties:
- if prop.name in path and len(prop.values) > 0:
- path = path.replace(prop.name, prop.values[0])
-
- return self.root().get_by_path(path)
-
- @staticmethod
- # pylint: disable=arguments-differ
- def from_dts(dts: str) -> 'Devicetree':
- """Parse a string and return a Devicetree object"""
- # pylint: disable=import-outside-toplevel,cyclic-import
- from pydevicetree.source import parseTree
- return parseTree(dts)
-
- @staticmethod
- def parseFile(filename: str, followIncludes: bool = False) -> 'Devicetree':
- """Parse a file and return a Devicetree object"""
- # pylint: disable=import-outside-toplevel,cyclic-import
- from cot_dt2c.pydevicetree.source.parser import parseTree
- with open(filename, 'r') as f:
- contents = f.read()
- dirname = os.path.dirname(filename)
- if dirname != "":
- dirname += "/"
- return parseTree(contents, dirname, followIncludes)
-
- @staticmethod
- def parseStr(input: str, followIncludes: bool = False) -> 'Devicetree':
- from cot_dt2c.pydevicetree.source.parser import parseTree
- return parseTree(input, "", followIncludes)
-
- def all_nodes(self) -> Iterable[Node]:
- """Get an iterable over all nodes in the tree"""
- return self.child_nodes()
-
- def root(self) -> Node:
- """Get the root node of the tree"""
- for n in self.all_nodes():
- if n.name == "/":
- return n
- raise Exception("Devicetree has no root node!")
-
- def aliases(self) -> Optional[Node]:
- """Get the aliases node of the tree if it exists"""
- for n in self.all_nodes():
- if n.name == "aliases":
- return n
- return None
-
- def chosen(self, property_name: str, func: ChosenCallback = None) -> Optional[PropertyValues]:
- """Get the values associated with one of the properties in the chosen node"""
- def match_chosen(node: Node) -> bool:
- return node.name == "chosen"
-
- for n in filter(match_chosen, self.all_nodes()):
- for p in n.properties:
- if p.name == property_name:
- if func is not None:
- func(p.values)
- return p.values
-
- return None
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py
deleted file mode 100644
index d5fb687..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/property.py
+++ /dev/null
@@ -1,278 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-from typing import List, Any, cast, Tuple, Optional, Iterable
-from itertools import zip_longest
-
-from cot_dt2c.pydevicetree.ast.helpers import wrapStrings, formatLevel
-
-class PropertyValues:
- """PropertyValues is the parent class of all values which can be assigned to a Property
-
- Child classes include
-
- Bytestring
- CellArray
- StringList
- """
- def __init__(self, values: List[Any]):
- """Create a PropertyValue"""
- self.values = values
-
- def __repr__(self) -> str:
- return "<PropertyValues " + self.values.__repr__() + ">"
-
- def __str__(self) -> str:
- return self.to_dts()
-
- def __iter__(self):
- return iter(self.values)
-
- def __len__(self) -> int:
- return len(self.values)
-
- def to_dts(self, formatHex: bool = False) -> str:
- """Format the values in Devicetree Source format"""
- return ", ".join(wrapStrings(self.values, formatHex))
-
- def __getitem__(self, key) -> Any:
- return self.values[key]
-
- def __eq__(self, other) -> bool:
- if isinstance(other, PropertyValues):
- return self.values == other.values
- return self.values == other
-
-class Bytestring(PropertyValues):
- """A Bytestring is a sequence of bytes
-
- In Devicetree, Bytestrings are represented as a sequence of two-digit hexadecimal integers,
- optionally space-separated, enclosed by square brackets:
-
- [de ad be eef]
- """
- def __init__(self, bytelist: List[int]):
- """Create a Bytestring object"""
- PropertyValues.__init__(self, cast(List[Any], bytearray(bytelist)))
-
- def __repr__(self) -> str:
- return "<Bytestring " + str(self.values) + ">"
-
- def to_dts(self, formatHex: bool = False) -> str:
- """Format the bytestring in Devicetree Source format"""
- return "[" + " ".join("%02x" % v for v in self.values) + "]"
-
-class CellArray(PropertyValues):
- """A CellArray is an array of integer values
-
- CellArrays are commonly used as the value of Devicetree properties like `reg` and `interrupts`.
- The interpretation of each element of a CellArray is device-dependent. For example, the `reg`
- property encodes a CellArray as a list of tuples (base address, size), while the `interrupts`
- property encodes a CellArray as simply a list of interrupt line numbers.
- """
- def __init__(self, cells: List[Any]):
- """Create a CellArray object"""
- PropertyValues.__init__(self, cells)
-
- def __repr__(self) -> str:
- return "<CellArray " + self.values.__repr__() + ">"
-
- def to_dts(self, formatHex: bool = False) -> str:
- """Format the cell array in Devicetree Source format"""
- dtsValues = []
- for i in self.values:
- if not isinstance(i, OneString) and not isinstance(i, str):
- dtsValues.append(i)
- return "<" + " ".join(wrapStrings(dtsValues, formatHex)) + ">"
-
-class RegArray(CellArray):
- """A RegArray is the CellArray assigned to the reg property"""
- def __init__(self, cells: List[int],
- address_cells: int, size_cells: int,
- names: Optional[List[str]] = None):
- """Create a RegArray from a list of ints"""
- # pylint: disable=too-many-locals
- CellArray.__init__(self, cells)
- self.address_cells = address_cells
- self.size_cells = size_cells
-
- self.tuples = [] # type: List[Tuple[int, int, Optional[str]]]
-
- group_size = self.address_cells + self.size_cells
-
- if len(cells) % group_size != 0:
- raise Exception("CellArray does not contain enough cells")
-
- grouped_cells = [cells[i:i+group_size] for i in range(0, len(cells), group_size)]
-
- if not names:
- names = []
-
- for group, name in zip_longest(grouped_cells, cast(Iterable[Any], names)):
- address = 0
- a_cells = list(reversed(group[:self.address_cells]))
- for a, i in zip(a_cells, range(len(a_cells))):
- address += (1 << (32 * i)) * a
-
- size = 0
- s_cells = list(reversed(group[self.address_cells:]))
- for s, i in zip(s_cells, range(len(s_cells))):
- size += (1 << (32 * i)) * s
-
- self.tuples.append(cast(Tuple[int, int, Optional[str]], tuple([address, size, name])))
-
- def get_by_name(self, name: str) -> Optional[Tuple[int, int]]:
- """Returns the (address, size) tuple with a given name"""
- for t in self.tuples:
- if t[2] == name:
- return cast(Tuple[int, int], tuple(t[:2]))
- return None
-
- def __repr__(self) -> str:
- return "<RegArray " + self.values.__repr__() + ">"
-
- def __iter__(self) -> Iterable[Tuple[int, int]]:
- return cast(Iterable[Tuple[int, int]], map(lambda t: tuple(t[:2]), self.tuples))
-
- def __len__(self) -> int:
- return len(self.tuples)
-
- def __getitem__(self, key) -> Optional[Tuple[int, int]]:
- return list(self.__iter__())[key]
-
-class RangeArray(CellArray):
- """A RangeArray is the CellArray assigned to the range property"""
- def __init__(self, cells: List[int], child_address_cells: int,
- parent_address_cells: int, size_cells: int):
- """Create a RangeArray from a list of ints"""
- # pylint: disable=too-many-locals
- CellArray.__init__(self, cells)
- self.child_address_cells = child_address_cells
- self.parent_address_cells = parent_address_cells
- self.size_cells = size_cells
-
- self.tuples = [] # type: List[Tuple[int, int, int]]
-
- group_size = self.child_address_cells + self.parent_address_cells + self.size_cells
-
- if len(cells) % group_size != 0:
- raise Exception("CellArray does not contain enough cells")
-
- grouped_cells = [cells[i:i+group_size] for i in range(0, len(cells), group_size)]
-
- def sum_cells(cells: List[int]):
- value = 0
- for cell, index in zip(list(reversed(cells)), range(len(cells))):
- value += (1 << (32 * index)) * cell
- return value
-
- for group in grouped_cells:
- child_address = sum_cells(group[:self.child_address_cells])
- parent_address = sum_cells(group[self.child_address_cells: \
- self.child_address_cells + self.parent_address_cells])
- size = sum_cells(group[self.child_address_cells + self.parent_address_cells:])
-
- self.tuples.append(cast(Tuple[int, int, int],
- tuple([child_address, parent_address, size])))
-
- def __repr__(self) -> str:
- return "<RangeArray " + self.values.__repr__() + ">"
-
- def __iter__(self):
- return iter(self.tuples)
-
- def __len__(self) -> int:
- return len(self.tuples)
-
- def __getitem__(self, key) -> Any:
- return self.tuples[key]
-
-class StringList(PropertyValues):
- """A StringList is a list of null-terminated strings
-
- The most common use of a StringList in Devicetree is to describe the `compatible` property.
- """
- def __init__(self, strings: List[str]):
- """Create a StringList object"""
- PropertyValues.__init__(self, strings)
-
- def __repr__(self) -> str:
- return "<StringList " + self.values.__repr__() + ">"
-
- def to_dts(self, formatHex: bool = False) -> str:
- """Format the list of strings in Devicetree Source format"""
- return ", ".join(wrapStrings(self.values))
-
-class OneString(PropertyValues):
- def __init__(self, string: str):
- PropertyValues.__init__(self, string)
-
- def __repr__(self) -> str:
- return self.values.__repr__()
-
- def to_dts(self, formatHex: bool = False) -> str:
- return super().to_dts(formatHex)
-
-class Property:
- """A Property is a key-value pair for a Devicetree Node
-
- Properties are used to describe Nodes in the tree. There are many common properties, like
-
- - compatible
- - reg
- - reg-names
- - ranges
- - interrupt-controller
- - interrupts
- - interrupt-parent
- - clocks
- - status
-
- Which might commonly describe many or all nodes in a tree, and there are device, vendor,
- operating system, runtime-specific properties.
-
- Properties can possess no value, conveing meaning solely by their presence:
-
- interrupt-controller;
-
- Properties can also possess values such as an array of cells, a list of strings, etc.
-
- reg = <0x10013000 0x1000>;
- compatible = "sifive,rocket0", "riscv";
-
- And properties can posses arbitrarily complex values, such as the following from the
- Devicetree specification:
-
- example = <0xf00f0000 19>, "a strange property format";
- """
- def __init__(self, name: str, values: PropertyValues):
- """Create a Property object"""
- self.name = name
- self.values = values
-
- def __repr__(self) -> str:
- return "<Property %s>" % self.name
-
- def __str__(self) -> str:
- return self.to_dts()
-
- @staticmethod
- def from_dts(dts: str) -> 'Property':
- """Parse a file and return a Devicetree object"""
- # pylint: disable=import-outside-toplevel,cyclic-import
- from pydevicetree.source import parseProperty
- return parseProperty(dts)
-
- def to_dts(self, level: int = 0) -> str:
- """Format the Property assignment in Devicetree Source format"""
- if self.name in ["reg", "ranges"]:
- value = self.values.to_dts(formatHex=True)
- else:
- value = self.values.to_dts(formatHex=False)
-
- if value != "":
- return formatLevel(level, "%s = %s;\n" % (self.name, value))
- if self.name == "ifdef":
- return ""
- return formatLevel(level, "%s;\n" % self.name)
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py
deleted file mode 100644
index 54b2d28..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/ast/reference.py
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-from typing import Union, Iterator
-
-class Label:
- """A Label is a unique identifier for a Node
-
- For example, the following node has the label "uart0":
-
- uart0: uart@10013000 {
- ...
- };
- """
- def __init__(self, name: str):
- """Create a Label"""
- self.name = name
-
- def __repr__(self) -> str:
- return "<Label " + self.name + ">"
-
- def __eq__(self, other: object) -> bool:
- if isinstance(other, Label):
- return self.name == other.name
- if isinstance(other, str):
- return self.name == other
- return False
-
- def to_dts(self) -> str:
- """Format the label in Devicetree Source format"""
- return self.name + ":"
-
-class Path:
- """A Path uniquely identifies a Node by its parents and (optionally) unit address"""
- def __init__(self, path: str):
- """Create a path out of a string"""
- self.path = path
-
- def to_dts(self) -> str:
- """Format the Path in Devicetree Source format"""
- return self.path
-
- def __repr__(self) -> str:
- return "<Path " + self.to_dts() + ">"
-
- def __eq__(self, other: object) -> bool:
- if isinstance(other, Path):
- return self.to_dts() == other.to_dts()
- if isinstance(other, str):
- return self.to_dts() == other
- return False
-
- def __iter__(self) -> Iterator[str]:
- return iter(self.path.split("/"))
-
- def replace(self, old: str, new: str) -> 'Path':
- """Replace any elements of the path which match 'old' with a new element 'new'"""
- return Path(self.path.replace(old, new))
-
-class Reference:
- """A Reference is a Devicetree construct which points to a Node in the tree
-
- The following are types of references:
-
- - A reference to a label:
-
- &my-label;
-
- - A reference to a node by path:
-
- &{/path/to/node@deadbeef}
-
- This is the parent class for both types of references, LabelReference and PathReference
- """
- # pylint: disable=no-self-use
- def to_dts(self, formatHex: bool = False) -> str:
- """Format the Reference in Devicetree Source format"""
- return ""
-
-class LabelReference(Reference):
- """A LabelReference is a reference to a Node by label"""
- def __init__(self, label: Union[Label, str]):
- """Create a LabelReference from a Label or string"""
- if isinstance(label, Label):
- self.label = label
- elif isinstance(label, str):
- self.label = Label(label)
-
- def __repr__(self) -> str:
- return "<LabelReference " + self.to_dts() + ">"
-
- def to_dts(self, formatHex: bool = False) -> str:
- """Format the LabelReference in Devicetree Source format"""
- return "&" + self.label.name
-
-class PathReference(Reference):
- """A PathReference is a reference to a Node by path"""
- def __init__(self, path: Union[Path, str]):
- """Create a PathReference from a Path or string"""
- if isinstance(path, Path):
- self.path = path
- elif isinstance(path, str):
- self.path = Path(path)
-
- def __repr__(self) -> str:
- return "<PathReference " + self.to_dts() + ">"
-
- def to_dts(self, formatHex: bool = False) -> str:
- """Format the PathReference in Devicetree Source format"""
- return "&{" + self.path.to_dts() + "}"
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py
deleted file mode 100644
index 96768b3..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-from cot_dt2c.pydevicetree.source.parser import parseTree, parseNode, parseProperty
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py
deleted file mode 100644
index fb165e1..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/grammar.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-import os
-import sys
-
-import pyparsing as p # type: ignore
-
-ENV_CACHE_OPTION = "PYDEVICETREE_CACHE_SIZE_BOUND"
-
-cache_bound = None
-if ENV_CACHE_OPTION in os.environ:
- option = os.environ[ENV_CACHE_OPTION]
- if option != "None":
- try:
- cache_bound = int(option)
- except ValueError:
- print("%s requires a valid integer" % ENV_CACHE_OPTION, file=sys.stderr)
-p.ParserElement.enablePackrat(cache_bound)
-
-node_name = p.Word(p.alphanums + ",.-+_") ^ p.Literal("/")
-integer = p.pyparsing_common.integer ^ (p.Literal("0x").suppress() + p.pyparsing_common.hex_integer)
-unit_address = p.pyparsing_common.hex_integer
-unit_addresses = p.delimitedList(unit_address("address"), delim=",")
-node_handle = node_name("node_name") + p.Optional(p.Literal("@") + unit_addresses)
-property_name = p.Word(p.alphanums + ",.-_+?#")
-label = p.Word(p.alphanums + "_").setResultsName("label")
-label_creation = p.Combine(label + p.Literal(":"))
-string = p.QuotedString(quoteChar='"')
-stringlist = p.delimitedList(string)
-node_path = p.Combine(p.Literal("/") + \
- p.delimitedList(node_handle, delim="/", combine=True)).setResultsName("path")
-path_reference = p.Literal("&{").suppress() + node_path + p.Literal("}").suppress()
-label_reference = p.Literal("&").suppress() + label
-label_raw = p.Word(p.alphanums + "_")
-reference = path_reference ^ label_reference ^ label_raw
-include_directive = p.Literal("/include/") + p.QuotedString(quoteChar='"')
-generic_directive = p.QuotedString(quoteChar="/", unquoteResults=False) + \
- p.Optional(string ^ property_name ^ node_name ^ reference ^ (integer * 2)) + \
- p.Literal(";").suppress()
-directive = include_directive ^ generic_directive
-
-operator = p.oneOf("~ ! * / + - << >> < <= > >= == != & ^ | && ||")
-arith_expr = p.Forward()
-ternary_element = arith_expr ^ integer
-ternary_expr = ternary_element + p.Literal("?") + ternary_element + p.Literal(":") + ternary_element
-arith_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer) ^ ternary_expr))
-arth_str = p.Forward()
-arith_str_expr = p.nestedExpr(content=(p.OneOrMore(operator ^ integer ^ label_raw ^ p.Literal(",")) ^ ternary_expr))
-
-label_list = p.OneOrMore(p.Combine(label + p.Literal("\n")))
-
-cell_array = p.Literal("<").suppress() + \
- p.ZeroOrMore(integer ^ arith_expr ^ arith_str_expr ^ label_list ^ string ^ reference ^ label_creation.suppress()) + \
- p.Literal(">").suppress()
-bytestring = p.Literal("[").suppress() + \
- (p.OneOrMore(p.Word(p.hexnums, exact=2) ^ label_creation.suppress())) + \
- p.Literal("]").suppress()
-property_values = p.Forward()
-property_values = p.delimitedList(property_values ^ cell_array ^ bytestring ^ stringlist ^ \
- reference ^ label_raw)
-property_assignment = property_name("property_name") + p.Optional(p.Literal("=").suppress() + \
- (property_values)).setResultsName("value") + p.Optional(p.Literal(";").suppress())
-
-ifdef_label = p.ZeroOrMore(p.Word(p.alphanums + " _|//*=/(/)"))
-ifdef_define = p.Combine(p.Keyword("#if") + ifdef_label)
-ifdef_end = p.Combine(p.Keyword("#endif") + ifdef_label)
-ifdef_define_values = p.Forward()
-ifdef_define_values = p.ZeroOrMore(ifdef_define)
-ifdef_end_values = p.Forward()
-ifdef_end_values = p.ZeroOrMore(ifdef_end)
-
-node_opener = ifdef_define_values + p.Optional(label_creation) + node_handle + p.Literal("{").suppress()
-node_reference_opener = reference + p.Literal("{").suppress()
-node_closer = p.Literal("}").suppress() + p.Literal(";").suppress() + ifdef_end_values
-node_definition = p.Forward()
-# pylint: disable=expression-not-assigned
-node_definition << (node_opener ^ node_reference_opener) + \
- p.ZeroOrMore(property_assignment ^ directive ^ node_definition ^ ifdef_define ^ ifdef_end) + \
- node_closer
-
-devicetree = p.ZeroOrMore(directive ^ node_definition)
-
-devicetree.ignore(p.cStyleComment)
-devicetree.ignore("//" + p.SkipTo(p.lineEnd))
-devicetree.ignore("#include" + p.SkipTo(p.lineEnd))
-devicetree.ignore("#define" + p.SkipTo(p.lineEnd))
-devicetree.ignore("#else" + p.SkipTo(p.lineEnd))
-devicetree.ignore("#error" + p.SkipTo(p.lineEnd))
-devicetree.ignore("#ifndef" + p.SkipTo(p.lineEnd))
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- devicetree.parseFile(sys.argv[1]).pprint()
diff --git a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py b/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py
deleted file mode 100644
index 0692482..0000000
--- a/tools/cot_dt2c/cot_dt2c/pydevicetree/source/parser.py
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2019 SiFive Inc.
-# SPDX-License-Identifier: Apache-2.0
-
-from itertools import chain
-
-from cot_dt2c.pydevicetree.source import grammar
-from cot_dt2c.pydevicetree.ast import *
-
-ifdef_stack = []
-
-def transformNode(string, location, tokens):
- """Transforms a ParseResult into a Node"""
- properties = [e for e in tokens.asList() if isinstance(e, Property)]
- directives = [e for e in tokens.asList() if isinstance(e, Directive)]
- children = [e for e in tokens.asList() if isinstance(e, Node)]
-
- if isinstance(tokens[0], Reference):
- return NodeReference(tokens[0], properties=properties,
- directives=directives, children=children)
- return Node(tokens.node_name, tokens.label, tokens.address, properties=properties,
- directives=directives, children=children)
-
-def transformPropertyAssignment(string, location, tokens):
- """Transforms a ParseResult into a Property"""
- for v in tokens.value:
- if isinstance(v, PropertyValues):
- return Property(tokens.property_name, v)
- if isinstance(v, CellArray):
- return Property(tokens.property_name, v)
- if isinstance(v, StringList):
- return Property(tokens.property_name, v)
- if isinstance(v, Reference):
- return Property(tokens.property_name, v)
-
- return Property(tokens.property_name, PropertyValues([]))
-
-def transformDirective(string, location, tokens):
- """Transforms a ParseResult into a Directive"""
- if len(tokens.asList()) > 1:
- return Directive(tokens[0], tokens[1])
- return Directive(tokens[0])
-
-def evaluateArithExpr(string, location, tokens):
- """Evaluates a ParseResult as a python expression"""
- flat_tokens = list(chain.from_iterable(tokens.asList()))
- expr = " ".join(str(t) for t in flat_tokens)
- # pylint: disable=eval-used
- return eval(expr)
-
-def transformTernary(string, location, tokens):
- """Evaluates a ParseResult as a ternary expression"""
- # pylint: disable=eval-used
- return eval(str(tokens[2]) +" if " + str(tokens[0]) + " else " + str(tokens[4]))
-
-def transformPropertyValues(string, location, tokens):
- """Transforms a ParseResult into a PropertyValues"""
- if len(tokens.asList()) == 1:
- return tokens.asList()[0]
- return PropertyValues(tokens.asList())
-
-def transformStringList(string, location, tokens):
- """Transforms a ParseResult into a StringList"""
- return StringList(tokens.asList())
-
-def transformString(string, location, token):
- return OneString(token)
-
-def transformIfdefMacro(string, location, tokens):
- tokenlist = tokens.asList()
- for t in tokenlist:
- ifdef_stack.append(t)
- return Property("ifdef", PropertyValues(ifdef_stack.copy()))
-
-def transformIfdefEnd(string, location, tokens):
- tokenlist = tokens.asList()
- for t in tokenlist:
- ifdef_stack.pop()
-
-def transformIfdef(string, location, tokens):
- return Property("ifdef", PropertyValues(tokens))
-
-def evaluateStrArithExpr(string, location, tokens):
- """Evaluates a ParseResult as a python expression"""
- flat_tokens = list(chain.from_iterable(tokens.asList()))
- for i, t in enumerate(flat_tokens):
- if isinstance(t, int):
- flat_tokens[i] = "(" + str(t) + ")"
- expr = " ".join(str(t) for t in flat_tokens)
- # pylint: disable=eval-used
- return expr
-
-def transformBytestring(string, location, tokens):
- """Transforms a ParseResult into a Bytestring"""
- inttokens = []
- for t in tokens.asList():
- if all(c in "0123456789abcdefABCDEF" for c in t):
- inttokens.append(int(t, base=16))
- return Bytestring(inttokens)
-
-def transformCellArray(string, location, tokens):
- """Transforms a ParseResult into a CellArray"""
- return CellArray(tokens.asList())
-
-def transformLabel(string, location, tokens):
- """Transforms a ParseResult into a Label"""
- return Label(tokens.label)
-
-def transformPath(string, location, tokens):
- """Transforms a ParseResult into a Path"""
- path = ""
- for handle in tokens.path[0].split("/"):
- if "@" in handle:
- node, address = handle.split("@")
- path += "/%s@%x" % (node, int(address))
- elif handle != "":
- path += "/" + handle
- return Path(path)
-
-def transformPathReference(string, location, tokens):
- """Transforms a ParseResult into a PathReference"""
- return PathReference(tokens[0])
-
-def transformLabelReference(string, location, tokens):
- """Transforms a ParseResult into a LabelReference"""
- return LabelReference(tokens[0])
-
-def transformReference(string, location, tokens):
- """Transforms a ParseResult into a Reference"""
- if isinstance(tokens[0], Reference):
- return tokens[0]
- return None
-
-grammar.label.setParseAction(transformLabel)
-grammar.node_path.setParseAction(transformPath)
-grammar.path_reference.setParseAction(transformPathReference)
-grammar.label_reference.setParseAction(transformLabelReference)
-grammar.reference.setParseAction(transformReference)
-grammar.node_definition.setParseAction(transformNode)
-grammar.property_assignment.setParseAction(transformPropertyAssignment)
-grammar.directive.setParseAction(transformDirective)
-grammar.arith_expr.setParseAction(evaluateArithExpr)
-grammar.ternary_expr.setParseAction(transformTernary)
-grammar.stringlist.setParseAction(transformStringList)
-grammar.bytestring.setParseAction(transformBytestring)
-grammar.cell_array.setParseAction(transformCellArray)
-grammar.property_values.setParseAction(transformPropertyValues)
-grammar.label_raw.setParseAction(transformString)
-grammar.ifdef_define_values.setParseAction(transformIfdefMacro)
-grammar.ifdef_end_values.setParseAction(transformIfdefEnd)
-grammar.arith_str_expr.setParseAction(transformPropertyValues)
-
-def printTree(tree, level=0):
- """Helper function to print a bunch of elements as a tree"""
- def printlevel(level, s):
- print(" " * level + s)
-
- for item in tree:
- if isinstance(item, Node):
- if item.address:
- printlevel(level, "Node %s@%x" % (item.name, item.address))
- else:
- printlevel(level, "Node %s" % item.name)
-
- if item.label:
- printlevel(level, " Label: %s" % item.label)
-
- if item.parent:
- printlevel(level, " Parent: %s" % item.parent)
-
- printTree(item.properties, level=(level + 1))
-
- printTree(item.children, level=(level + 1))
- elif isinstance(item, Property):
- if item.values:
- printlevel(level, "Property %s: %s" % (item.name, item.values))
- else:
- printlevel(level, "Property %s" % item.name)
- elif isinstance(item, Directive):
- if item.options:
- printlevel(level, "Directive %s: %s" % (item.directive, item.options))
- else:
- printlevel(level, "Directive %s" % item.directive)
-
-def parentNodes(tree, parent=None):
- """Walks a tree and sets Nodes' parent field to point at their parent"""
- for item in tree:
- if isinstance(item, Node):
- item.parent = parent
- parentNodes(item.children, item)
-
-def recurseIncludeFiles(elements, pwd):
- """Recursively follows and parses /include/ directives an a tree"""
- for e in elements:
- if isinstance(e, Directive):
- if e.directive == "/include/":
- # Prefix with current directory if path is not absolute
- if e.option[0] != '/':
- e.option = pwd + e.option
-
- with open(e.option, 'r') as f:
- contents = f.read()
-
- elements += parseElements(contents)
-
- del elements[elements.asList().index(e)]
-
-def parseElements(dts, pwd="", followIncludes=False):
- """Parses a string into a list of elements"""
- elements = grammar.devicetree.parseString(dts, parseAll=True)
- parentNodes(elements)
- if followIncludes:
- recurseIncludeFiles(elements, pwd)
- return elements
-
-def parseTree(dts, pwd="", followIncludes=False):
- """Parses a string into a full Devicetree"""
- return Devicetree(parseElements(dts, pwd, followIncludes))
-
-def parseNode(dts):
- """Parses a string into a Devictreee Node"""
- return grammar.node_definition.parseString(dts, parseAll=True)[0]
-
-def parseProperty(dts):
- """Parses a string into a Devicetree Property"""
- return grammar.property_assignment.parseString(dts, parseAll=True)[0]
-
-if __name__ == "__main__":
- import sys
- if len(sys.argv) > 1:
- with open(sys.argv[1], 'r') as f:
- dts = f.read()
- tree = parseTree(dts)
- printTree(tree)
- print(tree)
- else:
- print("Please pass the devicetree source file as an argument")
- sys.exit(1)
diff --git a/tools/cot_dt2c/poetry.lock b/tools/cot_dt2c/poetry.lock
new file mode 100644
index 0000000..df58d54
--- /dev/null
+++ b/tools/cot_dt2c/poetry.lock
@@ -0,0 +1,334 @@
+# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
+
+[[package]]
+name = "atomicwrites"
+version = "1.4.1"
+description = "Atomic file writes."
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+files = [
+ {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
+]
+
+[[package]]
+name = "attrs"
+version = "24.2.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
+ {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
+]
+
+[package.extras]
+benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
+tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
+
+[[package]]
+name = "click"
+version = "8.1.7"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
+ {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "igraph"
+version = "0.11.6"
+description = "High performance graph data structures and algorithms"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "igraph-0.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3f8b837181e8e87676be3873ce87cc92cc234efd58a2da2f6b4e050db150fcf4"},
+ {file = "igraph-0.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:245c4b7d7657849eff80416f5df4525c8fc44c74a981ee4d44f0ef2612c3bada"},
+ {file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdb7be3d165073c0136295c0808e9edc57ba096cdb26e94086abb04561f7a292"},
+ {file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58974e20df2986a1ae52a16e51ecb387cc0cbeb41c5c0ddff4d373a1bbf1d9c5"},
+ {file = "igraph-0.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bef14de5e8ab70724a43808b1ed14aaa6fe1002f87e592289027a3827a8f44a"},
+ {file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:86c1e98de2e32d074df8510bf18abfa1f4c5fda4cb28a009985a5d746b0c0125"},
+ {file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ebc5b3d702158abeb2e4d2414374586a2b932e1a07e48352b470600e1733d528"},
+ {file = "igraph-0.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0efe6d0fb22d3987a800eb3857ed04df9eb4c5dddd0998be05232cb646f1c337"},
+ {file = "igraph-0.11.6-cp38-cp38-win32.whl", hash = "sha256:f4e68b27497b1c8ada2fb2bc35ef3fa7b0d72e84306b3d648d3de240fc618c32"},
+ {file = "igraph-0.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:5665b33dfbfca5f54ce9b4fea6b97903bd0e99fb1b02acf5e57e600bdfa5a355"},
+ {file = "igraph-0.11.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:8aabef03d787b519d1075dfc0da4a1109fb113b941334883e3e7947ac30a459e"},
+ {file = "igraph-0.11.6-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1f2cc4a518d99cdf6cae514f85e93e56852bc8c325b3abb96037d1d690b5975f"},
+ {file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e859238be52ab8ccc614d18f9362942bc88ce543afc12548f81ae99b10801d"},
+ {file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d61fbe5e85eb4ae9efe08c461f9bdeedb02a2b5739fbc223d324a71f40a28be2"},
+ {file = "igraph-0.11.6-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6620ba39df29fd42151becf82309b54e57148233c9c3ef890eed62e25eed8a5"},
+ {file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59666589bb3d07f310cda2c5106a8adeeb77c2ef27fecf1c6438b6091f4ca69d"},
+ {file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:8750b6d6caebf199cf7dc41c931f58e330153779707391e30f0a29f02666fb6e"},
+ {file = "igraph-0.11.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:967d6f2c30fe94317da15e459374d0fb8ca3e56020412f201ecd07dd5b5352f2"},
+ {file = "igraph-0.11.6-cp39-abi3-win32.whl", hash = "sha256:9744f95a67319eb6cb487ceabf30f5d7940de34bada51f0ba63adbd23e0f94ad"},
+ {file = "igraph-0.11.6-cp39-abi3-win_amd64.whl", hash = "sha256:b80e69eb11faa9c57330a9ffebdde5808966efe1c1f638d4d4827ea04df7aca8"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0329c16092e2ea7930d5f8368666ce7cb704900cc0ea04e4afe9ea1dd46e44af"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21752313f449bd8688e5688e95ea7231cea5e9199c7162535029be0d9af848ac"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea25e136c6c4161f53ff58868b23ff6c845193050ab0e502236d68e5d4174e32"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac84433a03aef15e4b810010b08882b09854a3669450ccf31e392dbe295d2a66"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac697a44e3573169fa2b28c9c37dcf9cf01e0f558b845dd7123860d4c7c8fb89"},
+ {file = "igraph-0.11.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bdeae8bf35316eb1fb27bf667dcf5ecf5fcfb0b8f51831bc1b00c39c09c2d73b"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ad7e4aa442935de72554b96733bf6d7f09eac5cee97988a2562bdd3ca173cfa3"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d2818780358a686178866d01568b9df1f29678581734ad7a78882bab54df004"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2352276a20d979f1dea360af4202bb9f0c9a7d2c77f51815c0e625165e82013d"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:687fdab543b507d622fa3043f4227e5b26dc61dcf8ff8c0919fccddcc655f8b8"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57f7f8214cd48c9a4d97f7346a4152ba2d4ac95fb5ee0df4ecf224fce4ba3d14"},
+ {file = "igraph-0.11.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2b9cc69ede53f76ffae03b066609aa90184dd68ef15da8c104a97cebb9210838"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:591e1e447c3f0092daf7613a3eaedab83f9a0b0adbaf7702724c5117ded038a5"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ca558eb331bc687bc33e5cd23717e22676e9412f8cda3a31d30c996a0487610d"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf43c30e08debb087c9e3da69aa5cf1b6732968da34d55a614e3421b9a452146"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d38e8d7db72b187d9d2211d0d06b3271fa9f32b04d49d789e2859b5480db0d0"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a318b059051ff78144a1c3cb880f4d933c812bcdb3d833a49cd7168d0427672"},
+ {file = "igraph-0.11.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2c54027add809b3c5b6685b8deca4ea4763fd000b9ea45c7ee46b7c9d61ff15e"},
+ {file = "igraph-0.11.6.tar.gz", hash = "sha256:837f233256c3319f2a35a6a80d94eafe47b43791ef4c6f9e9871061341ac8e28"},
+]
+
+[package.dependencies]
+texttable = ">=1.6.2"
+
+[package.extras]
+cairo = ["cairocffi (>=1.2.0)"]
+doc = ["Sphinx (>=7.0.0)", "pydoctor (>=23.4.0)", "sphinx-gallery (>=0.14.0)", "sphinx-rtd-theme (>=1.3.0)"]
+matplotlib = ["matplotlib (>=3.6.0)"]
+plotly = ["plotly (>=5.3.0)"]
+plotting = ["cairocffi (>=1.2.0)"]
+test = ["Pillow (>=9)", "cairocffi (>=1.2.0)", "matplotlib (>=3.6.0)", "networkx (>=2.5)", "numpy (>=1.19.0)", "pandas (>=1.1.0)", "plotly (>=5.3.0)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)", "scipy (>=1.5.0)"]
+test-musl = ["cairocffi (>=1.2.0)", "networkx (>=2.5)", "pytest (>=7.0.1)", "pytest-timeout (>=2.1.0)"]
+
+[[package]]
+name = "iniconfig"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
+ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
+]
+
+[[package]]
+name = "mypy"
+version = "0.910"
+description = "Optional static typing for Python"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"},
+ {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"},
+ {file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"},
+ {file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"},
+ {file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"},
+ {file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"},
+ {file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"},
+ {file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"},
+ {file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"},
+ {file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"},
+ {file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"},
+ {file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"},
+ {file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"},
+ {file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"},
+ {file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"},
+ {file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"},
+ {file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"},
+ {file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"},
+ {file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"},
+ {file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"},
+ {file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"},
+ {file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"},
+ {file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"},
+]
+
+[package.dependencies]
+mypy-extensions = ">=0.4.3,<0.5.0"
+toml = "*"
+typing-extensions = ">=3.7.4"
+
+[package.extras]
+dmypy = ["psutil (>=4.0)"]
+python2 = ["typed-ast (>=1.4.0,<1.5.0)"]
+
+[[package]]
+name = "mypy-extensions"
+version = "0.4.4"
+description = "Experimental type system extensions for programs checked with the mypy typechecker."
+optional = false
+python-versions = ">=2.7"
+files = [
+ {file = "mypy_extensions-0.4.4.tar.gz", hash = "sha256:c8b707883a96efe9b4bb3aaf0dcc07e7e217d7d8368eec4db4049ee9e142f4fd"},
+]
+
+[[package]]
+name = "packaging"
+version = "24.1"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
+ {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
+]
+
+[[package]]
+name = "plotly"
+version = "5.23.0"
+description = "An open-source, interactive data visualization library for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "plotly-5.23.0-py3-none-any.whl", hash = "sha256:76cbe78f75eddc10c56f5a4ee3e7ccaade7c0a57465546f02098c0caed6c2d1a"},
+ {file = "plotly-5.23.0.tar.gz", hash = "sha256:89e57d003a116303a34de6700862391367dd564222ab71f8531df70279fc0193"},
+]
+
+[package.dependencies]
+packaging = "*"
+tenacity = ">=6.2.0"
+
+[[package]]
+name = "pluggy"
+version = "1.5.0"
+description = "plugin and hook calling mechanisms for python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
+ {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
+]
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "py"
+version = "1.11.0"
+description = "library with cross-python path, ini-parsing, io, code, log facilities"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
+ {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
+]
+
+[[package]]
+name = "pydevicetree"
+version = "0.0.13"
+description = "A library for parsing Devicetree Source v1"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "pydevicetree-0.0.13-py3-none-any.whl", hash = "sha256:d61c695cec925b90a8b5740053f4b604e51154a9b36e62a2f12ed9ceaf2f8c38"},
+ {file = "pydevicetree-0.0.13.tar.gz", hash = "sha256:5700c05df89bad8fd729c11aa6f764a3323bcb3796f13b32481ae34445cfc1b7"},
+]
+
+[package.dependencies]
+pyparsing = "*"
+
+[[package]]
+name = "pyparsing"
+version = "3.1.2"
+description = "pyparsing module - Classes and methods to define and execute parsing grammars"
+optional = false
+python-versions = ">=3.6.8"
+files = [
+ {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"},
+ {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"},
+]
+
+[package.extras]
+diagrams = ["jinja2", "railroad-diagrams"]
+
+[[package]]
+name = "pytest"
+version = "6.2.5"
+description = "pytest: simple powerful testing with Python"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
+ {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
+]
+
+[package.dependencies]
+atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
+attrs = ">=19.2.0"
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=0.12,<2.0"
+py = ">=1.8.2"
+toml = "*"
+
+[package.extras]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+
+[[package]]
+name = "tenacity"
+version = "9.0.0"
+description = "Retry code until it succeeds"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539"},
+ {file = "tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b"},
+]
+
+[package.extras]
+doc = ["reno", "sphinx"]
+test = ["pytest", "tornado (>=4.5)", "typeguard"]
+
+[[package]]
+name = "texttable"
+version = "1.7.0"
+description = "module to create simple ASCII tables"
+optional = false
+python-versions = "*"
+files = [
+ {file = "texttable-1.7.0-py2.py3-none-any.whl", hash = "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917"},
+ {file = "texttable-1.7.0.tar.gz", hash = "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638"},
+]
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+description = "Python Library for Tom's Obvious, Minimal Language"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
+ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.12.2"
+description = "Backported and Experimental Type Hints for Python 3.8+"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
+ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
+]
+
+[metadata]
+lock-version = "2.0"
+python-versions = "^3.8"
+content-hash = "afa5cb49be96467a848bab753a630c6f5ec42d6750d67d29920c3e3971774e36"
diff --git a/tools/cot_dt2c/pyproject.toml b/tools/cot_dt2c/pyproject.toml
index d383924..73251d7 100644
--- a/tools/cot_dt2c/pyproject.toml
+++ b/tools/cot_dt2c/pyproject.toml
@@ -28,30 +28,33 @@
[tool.poetry.dependencies]
python = "^3.8"
click = "^8.1.7"
-pyparsing = "^2.4.7"
plotly = "^5.23.0"
-pandas = "^2.2.2"
+pydevicetree = "0.0.13"
igraph = "^0.11.6"
+pyparsing = "^3.1.2"
-[tool.poetry.dev-dependencies]
+[tool.poetry.group.dev]
+optional = true
+
+[tool.poetry.group.dev.dependencies]
mypy = "^0.910"
pytest = "^6.2.5"
-pyparsing = "^2.4.7"
-plotly = "^5.23.0"
-pandas = "^2.2.2"
-igraph = "^0.11.6"
[tool.mypy]
# https://mypy.readthedocs.io/en/latest/config_file.html#using-a-pyproject-toml-file
-python_version = 3.8
+python_version = "3.8"
pretty = true
show_traceback = true
color_output = true
+[[tool.mypy.overrides]]
+module = ["igraph", "pydevicetree", "pydevicetree.ast", "plotly", "plotly.graph_objects"]
+ignore_missing_imports = true
+
[tool.coverage.run]
source = ["tests"]
-[coverage.paths]
+[tool.coverage.paths]
source = "cot_dt2c"
[tool.poetry.scripts]
diff --git a/tools/cot_dt2c/requirements.txt b/tools/cot_dt2c/requirements.txt
deleted file mode 100644
index 246b81d..0000000
--- a/tools/cot_dt2c/requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-mypy
-pylint
-pyparsing
-igraph
-pandas
-plotly