{"id":20446313,"url":"https://github.com/rust-embedded/svdtools","last_synced_at":"2025-05-16T14:07:16.847Z","repository":{"id":35067870,"uuid":"202885083","full_name":"rust-embedded/svdtools","owner":"rust-embedded","description":"Python package to handle vendor-supplied, often buggy SVD files.","archived":false,"fork":false,"pushed_at":"2025-04-26T03:51:59.000Z","size":827,"stargazers_count":87,"open_issues_count":30,"forks_count":36,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-26T04:43:25.513Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rust-embedded.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG-python.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-08-17T13:35:30.000Z","updated_at":"2025-04-14T06:37:35.000Z","dependencies_parsed_at":"2023-11-28T20:26:57.493Z","dependency_job_id":"43382ea5-9f18-4e7f-bf3d-d6daba86f2fd","html_url":"https://github.com/rust-embedded/svdtools","commit_stats":null,"previous_names":["rust-embedded/svdtools","stm32-rs/svdtools"],"tags_count":69,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-embedded%2Fsvdtools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-embedded%2Fsvdtools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-embedded%2Fsvdtools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rust-embedded%2Fsvdtools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rust-embedded","download_url":"https://codeload.github.com/rust-embedded/svdtools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254544146,"owners_count":22088807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T10:19:13.582Z","updated_at":"2025-05-16T14:07:16.828Z","avatar_url":"https://github.com/rust-embedded.png","language":"Rust","readme":"![GitHub top language](https://img.shields.io/github/languages/top/rust-embedded/svdtools)\n![Minimum Supported Rust Version](https://img.shields.io/badge/rustc-1.70+-blue.svg)\n[![crates.io](https://img.shields.io/crates/v/svdtools.svg)](https://crates.io/crates/svdtools)\n[![crates.io](https://img.shields.io/crates/d/svdtools.svg)](https://crates.io/crates/svdtools)\n[![Released API docs](https://docs.rs/svdtools/badge.svg)](https://docs.rs/svdtools)\n![Crates.io](https://img.shields.io/crates/l/svdtools)\n[![dependency status](https://deps.rs/repo/github/rust-embedded/svdtools/status.svg)](https://deps.rs/repo/github/rust-embedded/svdtools)\n[![Continuous integration](https://github.com/rust-embedded/svdtools/workflows/Continuous%20integration/badge.svg)](https://github.com/rust-embedded/svdtools)\n\n# svdtools\n\n**svdtools** is a set of tools for modifying vendor-supplied, often buggy SVD\nfiles. It can be imported as a library for use in other applications, or run\ndirectly via the included `svdtools` CLI utility.\n\nA common use case is patching vendor-supplied SVD files, then applying\n[svd2rust](https://github.com/rust-embedded/svd2rust) to the resulting patched\nSVD.\n\nThis project is developed and maintained by the [Tools team][team].\n\n## Getting Started with Python version\n\nPython 3.6 or newer is required to install and use `svdtools`. To install:\n\n```bash\n$ pip3 install --upgrade --user svdtools\n```\n\nOnce installation has completed, the `svd` utility can be called from the command line.\n\nAn example is given in `make example`, which calls\n`svd patch example/incomplete-stm32l4x2.yaml` and generates a patched SVD file\n`example/stm32l4x2.svd.patched`.\n\nSee [Device and Peripheral YAML Format](#device-and-peripheral-yaml-format) for\nmore information on creating patches.\n\n## Getting Started with Rust version\n\nThis crate is guaranteed to compile on stable Rust 1.58.0 and up. To install:\n\n```bash\n$ cargo install svdtools\n```\n\nOnce installation has completed, the `svdtools` utility can be called from the command line. Command line interface is same as CLI for Python version.\n\n## Develop\n\nTo each their own, but the intended workflow is as follows:\n\n1. Setup a virtual environment via `make setup`; this also installs the `svd` CLI\n2. Activate the virtual environment by running `source venv/bin/activate` (or use [direnv](https://direnv.net/))\n3. Iterate, running `make check` and `make fix` as necessary\n\n\n## Device and Peripheral YAML Format\n\nThe patch specifications are in [YAML](https://yaml.org/), and have the following\ngeneral format:\n\n```yaml\n# Path to the SVD file we're targeting. Relative to this file.\n# This must be included only in the device YAML file.\n_svd: \"../svd/STM32F0x0.svd\"\n\n# Include other YAML files. Path relative to this file.\n_include:\n    - \"../peripherals/gpio_v2.yaml\"\n\n# Alter top-level information and peripherals for this device\n_modify:\n    version: 1.1\n    description: bla bla\n    addressUnitBits: 8\n    width: 32\n    cpu:\n        revision: r1p2\n        mpuPresent: true\n    # Peripherals can either live directly at this level (but other top-level\n    # fields will name match first)\n    C_ADC:\n        name: ADC_Common\n    # Or they can be inside a _peripherals block, to avoid name conflicts.\n    _peripherals:\n        FSMC:\n            description: Flexible static memory controller\n\n            # Multiple address blocks are supported via the addressBlocks list\n            # use either addressBlock or addressBlocks, but not both\n            addressBlocks:\n                -   offset: 0x0\n                    size: 0x400\n                    usage: \"ADC base registers\"\n                -   offset: 0x1000\n                    size: 0x400\n                    usage: \"ADC extra registers\"\n\n\n\n# Add whole new peripherals to this device.\n# Incredibly this feature is required.\n_add:\n    ADC_Common:\n        description: ADC Common registers\n        groupName: ADC\n        baseAddress: 0x40012300\n        addressBlock:\n            offset: 0x0\n            size: 0x400\n            usage: \"All ADC registers\"\n        # Multiple address blocks are supported via the addressBlocks list\n        addressBlocks:\n            -   offset: 0x0\n                size: 0x400\n                usage: \"ADC base registers\"\n            -   offset: 0x1000\n                size: 0x400\n                usage: \"ADC extra registers\"\n        registers:\n            CSR:\n                description: ADC Common status register\n                addressOffset: 0x0\n                access: read-only\n                resetValue: 0x00000000\n                fields:\n                    OVR3:\n                        description: Overrun flag of ADC3\n                        bitOffset: 21\n                        bitWidth: 1\n        interrupts:\n            ADC1_2:\n                description: ADC global interrupt\n                value: 18\n\n# A whole new peripheral can also be created as derivedFrom another peripheral.\n_add:\n    USART3:\n        derivedFrom: USART1\n        baseAddress: \"0x40004800\"\n        interrupts:\n            USART3:\n                description: USART3 global interrupt\n                value: 39\n\n# A new peripheral can have all its registers copied from another, in case\n# it cannot quite be derivedFrom (e.g. some fields need different enumerated\n# values) but it's otherwise almost exactly the same.\n# The registers are copied but not name or address or interrupts, which are\n# preserved if the target already exists.\n_copy:\n    ADC3:\n        from: ADC2\n\n# The new peripheral can also be copied from another svd file for a different\n# device. This is useful when a peripheral is missing in a device but the exact\n# same peripheral already exist in another device.\n# When copying from another file, all fields including interrupts are copied.\n_copy:\n    TIM1:\n        from: ../svd/stm32f302.svd:TIM1\n\n# Replace peripheral registers by a 'deriveFrom'.\n# This is used when e.g. UART4 and UART5 are both independently defined,\n# but you'd like to make UART5 be defined as derivedFrom UART4 instead.\n_derive:\n    # The KEY peripheral looses all its elements but 'interrupt', 'name',\n    # and 'baseAddress', and it is derivedFrom the VALUE peripheral.\n    # Peripherals that were 'deriveFrom=\"KEY\"' are now 'deriveFrom=\"VALUE\"'.\n    UART5: UART4\n\n# Reorder the hierarchy of peripherals with 'deriveFrom'.\n# This is used when e.g. I2C1 is marked as derivedFrom I2C3,\n# but you'd like to swap that so that I2C3 becomes derivedFrom I2C1.\n_rebase:\n    # The KEY peripheral steals everything but 'interrupt', 'name',\n    # and 'baseAddress' elements from the VALUE peripheral.\n    # Peripherals that were 'deriveFrom=\"VALUE\"' are now 'deriveFrom=\"KEY\"'.\n    # The VALUE peripheral is marked as derivedFrom the updated KEY.\n    I2C1: I2C3\n\n# An STM32 peripheral, matches an SVD \u003cperipheral\u003e tag.\n# Does not match any tag with derivedFrom attribute set.\n\"GPIO*\":\n    # We can include other YAML files inside this peripheral\n    _include:\n        - \"path/to/file.yaml\"\n\n    # Alter fields on existing registers inside this peripheral\n    _modify:\n        # Rename this badly named register. Takes effect before anything else.\n        # Don't use wildcard matches if you are changing the name!\n        # We could have specified name or description or other tags to update.\n        GPIOB_OSPEEDR:\n          name: OSPEEDR\n        # Equivalently the register could go in a '_registers' block\n        _registers:\n            GPIOB_OSPEEDR:\n                name: OSPEEDR\n        # Change the value of an interrupt in this peripheral\n        _interrupts:\n            EXTI0:\n                value: 101\n\n\n    # Add new registers and interrupts to this peripheral.\n    # Entries are registers by default, which can also go inside a '_registers'\n    # block, or interrupts go in an '_interrupts' block.\n    _add:\n        EXAMPLER:\n            description: An example register\n            addressOffset: 0x04\n            access: read-write\n            fields:\n                EXR1:\n                    description: Example field\n                    bitOffset: 16\n                    bitWidth: 4\n        _registers:\n            EXAMPLR2:\n                description: Another example register\n        _interrupts:\n            EXAMPLEI:\n                description: An example interrupt\n                value: 100\n\n    # Anywhere you can '_add' something, you can also '_delete' it.\n    # Wildcards are supported. The value here can be a YAML list of registers\n    # to delete (supported for backwards compatibility), or a YAML mapping\n    # of lists of registers or interrupts.\n    _delete:\n        GPIO*_EXTRAR:\n        _registers:\n            - GPIO*_EXAMPLER\n        _interrupts:\n            - USART1\n\n    # If registers have unnecessary common prefix/postfix,\n    # you can clean it in all registers in peripheral by:\n    _strip:\n        - \"PREFIX_*_\"\n    _strip_end:\n        - \"_POSTFIX_\"\n\n    # You can collect several same registers into one register array\n    # that will be represented with svd2rust as array or elements\n    # with one type\n    # Minimal version:\n    _array:\n        ARRAY*: {}\n\n    # You can also use the modifiers shown below:\n    _array:\n        ARRAY*:\n            name: NEW_NAME%s\n            _modify:\n                FIELD:\n                  description: NEWDESC\n        OTHER_ARRAY*: {}\n\n    # If you have registers that make up a group and can be repeated,\n    # you can collect them into cluster like this:\n    _cluster:\n        CLUSTER%s:\n            FIRST_REG: {}\n            SECOND_REG: {}\n\n    # clusters can be expanded into individual registers. The name of the resulting register will be the cluster name, concatenated with the register name.\n\n    _expand_cluster:\n        - CLUSTER_ONE*\n        - CLUSTER_TWO*\n\n    # When expanding clusters containing more than one element (as specified by \u003cdim\u003e), each register will have substutute [%] in the cluster name with its index number. If the cluster has a dimIndex element, a %s in the  cluster name will be replaced by dimIndex element. [%] is not compatible with dimIndex, as according to SVD 1.3.10\n    # The SVD 1.3.10 does not specify a delimiter for expansion, so passing the following parameters to the cluster as a hash will allow you to set the delimiter before and after the index is applied (the default delimiters are \"_\". You can also force the cluster to apply a zero index to a cluster with a single element by passing in the _zeroindex: true parameter\n\n    _expand_cluster:\n        CLUSTER_ONE*:\n        CLUSTER_TWO*:\n          _preindex: \"_\"\n          _postindex: \"_\"\n          _zeroindex: true\n\n\n    # if you pass the _noprefix: true parameter to a cluster, the cluster name will not be prefixed with the peripheral name. This is only valid for single element clusters.\n\n    _expand_cluster:\n        CLUSTER_ONE*:\n          _noprefix: true\n\n    # A register on this peripheral, matches an SVD \u003cregister\u003e tag\n    MODER:\n        # As in the peripheral scope, rename or redescribe a field.\n        # Don't use wildcard matches if you are changing the name!\n        _modify:\n            FIELD:\n              description: NEWDESC\n\n              # Change the writeConstraint of a field to enumerateValues\n              _write_constraint: \"enum\"\n\n              # Remove any writeConstraint from this field\n              _write_constraint: \"none\"\n\n              # Change the writeConstraint of a field to a range of values\n              _write_constraint: [MINIMUM, MAXIMUM]\n\n        # Add new fields to this register\n        _add:\n            NEWFIELD:\n              description: DESCRIPTION\n              bitOffset: 12\n              bitWidth: 4\n              access: read-write\n\n        # Often fields that should be one contiguous integer are specified\n        # as a number of individual bits instead. This merges any matching\n        # registers into a single field with the combined bitwidth and lowest\n        # bit offset, and the shared description and access.\n        _merge:\n            - \"FIELD*\"\n\n        # You can also merge fields with different base name like this:\n        _merge:\n            FIELD: [FIELD1, FIELD_?]\n        # Or like this:\n        _merge:\n            FIELD:\n                - FIELD1\n                - FIELD_?\n        # Or even like this:\n        _merge:\n            NEW_FIELD: \"FIELD*\"\n\n        # A field in this register, matches an SVD \u003cfield\u003e tag\n        FIELD:\n            # You can optionally specify name for `enumeratedValues`\n            _name: NAME\n            # By giving the field a dictionary we construct an enumerateValues\n            VARIANT: [VALUE, DESCRIPTION]\n            VARIANT: [VALUE, DESCRIPTION]\n            # Use `-1` for \"default\" variant which will be consider\n            # for all other values that are not listed explicitly\n            # usually datasheet marks them `0b0xxx`, `0b1x`, etc.\n            VARIANT: [-1, DESCRIPTION]\n\n        FIELD:\n            # If a field already has enumerateValues, drop them and\n            # replace them with entirely new ones.\n            _replace_enum:\n                VARIANT: [VALUE, DESCRIPTION]\n                VARIANT: [VALUE, DESCRIPTION]\n\n        # Another field. A list of two numbers gives a range writeConstraint.\n        FIELD: [MINIMUM, MAXIMUM]\n\n        # Another field with separate enumerated values for read and write\n        FIELD:\n            _read:\n                VARIANT: [VALUE, DESCRIPTION]\n                VARIANT: [VALUE, DESCRIPTION]\n            _write:\n                VARIANT: [VALUE, DESCRIPTION]\n                VARIANT: [VALUE, DESCRIPTION]\n        # Sometimes fields are to big so we need to split them into smaller fields\n        EXTI:\n          IMR:\n            # This would split MR into MRi where i = 0 ... bitlength\n            _split: [MR]\n            # This would split CHxFM into CHiFM where i = 0 ... bitlength\n            # and use the current bit for the description in each field\n            _split:\n              CHxFM:\n                name: CH%sFM\n                description: Processor 2 transmit channel %s free interrupt mask\n\n            # If fields have unnecessary common prefix/postfix,\n            # you can clean it in all registers in peripheral by:\n            _strip:\n                - \"PREFIX_*_\"\n            _strip_end:\n                - \"_POSTFIX_\"\n\n# You can list glob-like rules separated by commas to cover more periperals or registers at time.\n# If rule is optional (peripheral may be missing in some devices) add `?~` in the header.\n# Don't abuse it. First test not optional rule.\n\"?~TIM[18],TIM20\":\n  CR2:\n    # Fields also support collecting in arrays\n    _array:\n      OIS?:\n        description: Output Idle state (OC%s output)\n      # Optional rules are supported here too\n      \"?~OIS?N\":\n        description: Output Idle state (OC%sN output)\n```\n\n### Name Matching\n\nPeripheral, register, and field names can be specified:\n\n- Directly (eg. the full name of the peripheral/register/field)\n- Using `?` and `*` for single- and multi- character wildcards\n- Using `[ABC]` to give a list of possible matching characters\n- Using commas to separate a list of possible matches\n\nYou must quote the name if using any special characters in YAML.\n\nThe enumerated values `On` and `Off` are treated as a boolean in YAML and Python will throw the error:\n`AttributeError: 'bool' object has no attribute 'startswith'`, which does not give\nyou much information about where the error is. To avoid it, surround the values with\nquotes like any other special character.\n\n### Style Guide\n\n- Enumerated values should be named in the past tense (*enabled*, *masked*,\netc.)\n- Descriptions should start with capital letters and should not end with a period\n\n\n## License\n\nsvdtools is licensed under either of\n\n- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))\n- MIT License ([LICENSE-MIT](LICENSE-MIT))\n\nat your option.\n\n\n## Contribute\n\nPull requests are very welcome!\n\nPlease apply `black` and `isort` before committing. This can be accomplished by:\n- running `make fix`\n- running `black svdtools/` and `isort -y --recursive svdtools/`\n- installing an editor/IDE plugin\n\nThis avoids bikeshedding over formatting issues :)\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall\nbe dual licensed as above, without any additional terms or conditions.\n\n## Code of Conduct\n\nContribution to this crate is organized under the terms of the [Rust Code of\nConduct][CoC], the maintainer of this crate, the [Tools team][team], promises\nto intervene to uphold that code of conduct.\n\n[CoC]: CODE_OF_CONDUCT.md\n[team]: https://github.com/rust-embedded/wg#the-tools-team\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frust-embedded%2Fsvdtools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frust-embedded%2Fsvdtools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frust-embedded%2Fsvdtools/lists"}