Skip to content

test_register_inheritance_via_derived_from

For this feature, test cases cover scenarios where a derived register inherits properties from a base register, ensuring correct behavior when values are inherited.

test_circular_inheritance

This test case explores the scenario of circular inheritance, where RegisterA is defined to inherit from RegisterB, and RegisterB is, in turn, defined to inherit from RegisterA. This creates a circular reference loop, which is not a valid configuration. Circular inheritance would prevent the parser from resolving the properties of the registers correctly, as there would be no clear point of reference for the inherited attributes. The goal is to ensure that the parser detects such circular dependencies and raises an appropriate error to avoid an infinite loop or incorrect processing.

Expected Outcome: The parser should detect the circular inheritance between RegisterA and RegisterB and raise an error. This indicates that circular inheritance is not allowed, and the parser correctly identifies and prevents it from being processed. svdconv, can't process the file, since deriving from RegisterB is not possible due to forward referencing.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
@pytest.mark.xfail(strict=True, raises=ProcessException, reason="Circular inheritance is not supported")
def test_circular_inheritance(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case explores the scenario of circular inheritance, where `RegisterA` is defined to inherit from
    `RegisterB`, and `RegisterB` is, in turn, defined to inherit from `RegisterA`. This creates a circular
    reference loop, which is not a valid configuration. Circular inheritance would prevent the parser from
    resolving the properties of the registers correctly, as there would be no clear point of reference for the
    inherited attributes. The goal is to ensure that the parser detects such circular dependencies and raises an
    appropriate error to avoid an infinite loop or incorrect processing.

    **Expected Outcome:** The parser should detect the circular inheritance between `RegisterA` and `RegisterB` and
    raise an error. This indicates that circular inheritance is not allowed, and the parser correctly identifies
    and prevents it from being processed. `svdconv`, can't process the file, since deriving from `RegisterB` is
    not possible due to forward referencing.

    **Processable with svdconv:** no
    """

    get_processed_device_from_testfile("register_inheritance_via_derivedfrom/circular_inheritance.svd")
SVD file: register_inheritance_via_derivedfrom/circular_inheritance.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>circular_inheritance</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register derivedFrom="RegisterB">
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <addressOffset>0x4</addressOffset>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_derive_from_self

This test case evaluates a scenario where a register attempts to derive from itself, creating an invalid configuration. In the SVD file, RegisterA is defined with a derivedFrom attribute pointing to its own name. Such configurations should be detected as erroneous because a register cannot logically inherit properties from itself. This kind of self-reference should lead to a parsing error.

Expected Outcome: The parser should detect the invalid self-referential inheritance and raise an error, indicating that a register cannot derive from itself. This ensures that the system handles such configurations correctly by stopping further processing and informing the user of the issue.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
@pytest.mark.xfail(strict=True, raises=ProcessException, reason="Can't derive from self")
def test_derive_from_self(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case evaluates a scenario where a register attempts to derive from itself, creating an invalid
    configuration. In the SVD file, `RegisterA` is defined with a `derivedFrom` attribute pointing to its own
    name. Such configurations should be detected as erroneous because a register cannot logically inherit
    properties from itself. This kind of self-reference should lead to a parsing error.

    **Expected Outcome:** The parser should detect the invalid self-referential inheritance and raise an error,
    indicating that a register cannot derive from itself. This ensures that the system handles such configurations
    correctly by stopping further processing and informing the user of the issue.

    **Processable with svdconv:** no
    """

    get_processed_device_from_testfile("register_inheritance_via_derivedfrom/derive_from_self.svd")
SVD file: register_inheritance_via_derivedfrom/derive_from_self.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>derive_from_self</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register derivedFrom="RegisterA">
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_field_inheritance_overlap_bit_range

This test case examines the scenario where a derived register (RegisterB) inherits FieldA from a base register (RegisterA) and attempts to define a new field (FieldB) that occupies an overlapping bit range as an inherited field (FieldA). According to the SVD standard, fields within a register must not overlap in their bit ranges, and any such conflicts should be detected and flagged as errors. This test ensures that the parser correctly identifies the overlap and raises an appropriate error.

Expected Outcome: The parser should raise an error indicating that FieldA and FieldB cannot coexist because they overlap in their bit ranges. This behavior aligns with svdconv, which also detects and reports such conflicts. The parser's ability to catch this issue helps maintain the integrity of register definitions by preventing ambiguous or conflicting field configurations.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
@pytest.mark.xfail(
    strict=True,
    raises=ProcessException,
    reason="FieldA overlaps with FieldB",
)
def test_field_inheritance_overlap_bit_range(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case examines the scenario where a derived register (`RegisterB`) inherits `FieldA` from a base
    register (`RegisterA`) and attempts to define a new field (`FieldB`) that occupies an overlapping bit range as
    an inherited field (`FieldA`). According to the SVD standard, fields within a register must not overlap in
    their bit ranges, and any such conflicts should be detected and flagged as errors. This test ensures that the
    parser correctly identifies the overlap and raises an appropriate error.

    **Expected Outcome:** The parser should raise an error indicating that `FieldA` and `FieldB` cannot coexist
    because they overlap in their bit ranges. This behavior aligns with `svdconv`, which also detects and reports
    such conflicts. The parser's ability to catch this issue helps maintain the integrity of register definitions
    by preventing ambiguous or conflicting field configurations.

    **Processable with svdconv:** no
    """

    get_processed_device_from_testfile("register_inheritance_via_derivedfrom/field_inheritance_overlap_bit_range.svd")
SVD file: register_inheritance_via_derivedfrom/field_inheritance_overlap_bit_range.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>field_inheritance_overlap_bit_range</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <addressOffset>0x4</addressOffset>
          <fields>
            <field>
              <name>FieldB</name>
              <bitOffset>2</bitOffset>
              <bitWidth>4</bitWidth>
            </field>
          </fields>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_field_inheritance_same_bit_range

This test case examines the scenario where a derived register (RegisterB) inherits FieldA from a base register (RegisterA) and attempts to define a new field (FieldB) that occupies the same bit range as an inherited field (FieldA). According to the SVD standard, fields within a register must not overlap in their bit ranges, and any such conflicts should be detected and flagged as errors. This test ensures that the parser correctly identifies the overlap and raises an appropriate error.

Expected Outcome: The parser should raise an error indicating that FieldA and FieldB cannot coexist because they overlap in their bit ranges. This behavior aligns with svdconv, which also detects and reports such conflicts. The parser's ability to catch this issue helps maintain the integrity of register definitions by preventing ambiguous or conflicting field configurations.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
@pytest.mark.xfail(
    strict=True,
    raises=ProcessException,
    reason="FieldA overlaps with FieldB",
)
def test_field_inheritance_same_bit_range(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case examines the scenario where a derived register (`RegisterB`) inherits `FieldA` from a base
    register (`RegisterA`) and attempts to define a new field (`FieldB`) that occupies the same bit range as an
    inherited field (`FieldA`). According to the SVD standard, fields within a register must not overlap in their
    bit ranges, and any such conflicts should be detected and flagged as errors. This test ensures that the parser
    correctly identifies the overlap and raises an appropriate error.

    **Expected Outcome:** The parser should raise an error indicating that `FieldA` and `FieldB` cannot coexist
    because they overlap in their bit ranges. This behavior aligns with `svdconv`, which also detects and reports
    such conflicts. The parser's ability to catch this issue helps maintain the integrity of register definitions
    by preventing ambiguous or conflicting field configurations.

    **Processable with svdconv:** no
    """

    get_processed_device_from_testfile("register_inheritance_via_derivedfrom/field_inheritance_same_bit_range.svd")
SVD file: register_inheritance_via_derivedfrom/field_inheritance_same_bit_range.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>field_inheritance_same_bit_range</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <addressOffset>0x4</addressOffset>
          <fields>
            <field>
              <name>FieldB</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_field_inheritance_same_name

This test case evaluates the behavior of field inheritance when a derived register (RegisterB) attempts to define a field (FieldA) that shares the same name as a field inherited from its base register (RegisterA). According to SVD specifications, each field within a register should have a unique name, and inheriting a field with the same name as an existing field in the derived register leads to a conflict. The goal of this test is to ensure that the parser detects this scenario and raises an appropriate error.

Expected Outcome: The parser should raise an error, indicating that FieldA cannot be redefined in RegisterB because it already exists in the inherited properties from RegisterA. This behavior prevents conflicts in field definitions and maintains the integrity of the register's structure. Like svdconv, which also throws an error in this situation, the parser's explicit handling of this case ensures that users are clearly informed about the issue, guiding them to resolve such naming conflicts in their SVD files.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
@pytest.mark.xfail(
    strict=True,
    raises=ProcessException,
    reason="FieldA is already defined in RegisterA and cannot be inherited because it has the same name",
)
def test_field_inheritance_same_name(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case evaluates the behavior of field inheritance when a derived register (`RegisterB`) attempts to
    define a field (`FieldA`) that shares the same name as a field inherited from its base register (`RegisterA`).
    According to SVD specifications, each field within a register should have a unique name, and inheriting a
    field with the same name as an existing field in the derived register leads to a conflict. The goal of this
    test is to ensure that the parser detects this scenario and raises an appropriate error.

    **Expected Outcome:** The parser should raise an error, indicating that `FieldA` cannot be redefined in
    `RegisterB` because it already exists in the inherited properties from `RegisterA`. This behavior prevents
    conflicts in field definitions and maintains the integrity of the register's structure. Like `svdconv`, which
    also throws an error in this situation, the parser's explicit handling of this case ensures that users are
    clearly informed about the issue, guiding them to resolve such naming conflicts in their SVD files.

    **Processable with svdconv:** no
    """

    get_processed_device_from_testfile("register_inheritance_via_derivedfrom/field_inheritance_same_name.svd")
SVD file: register_inheritance_via_derivedfrom/field_inheritance_same_name.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>field_inheritance_same_name</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <addressOffset>0x4</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>3</bitOffset>
              <bitWidth>2</bitWidth>
            </field>
          </fields>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_multiple_inheritance_backward_reference

This test case evaluates the functionality of register inheritance when multiple derived registers inherit from a base register via backward references. In this scenario, RegisterA is defined as the base register with a specific set of attributes, including fields. RegisterB inherits from RegisterA, and RegisterC subsequently inherits from RegisterB. This chain of backward references ensures that RegisterC ultimately inherits properties from RegisterA through RegisterB. The SVD file clearly defines the inheritance structure, allowing each derived register to have a distinct address offset while maintaining the core properties from the base register.

Expected Outcome: The parser should correctly interpret the inheritance chain, ensuring that both RegisterB and RegisterC inherit all attributes from RegisterA. This means that RegisterB and RegisterC should have the same field (FieldA with bits 0 to 2) as defined in RegisterA. Each register should be positioned at their respective address offsets (0x0 for RegisterA, 0x4 for RegisterB, and 0x8 for RegisterC) with a size of 32 bits. The parsing should be consistent with the expected behavior of svdconv, which handles such backward reference chains correctly.

Processable with svdconv: yes

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
@pytest.mark.filterwarnings("error::svdsuite.process.ProcessWarning")
def test_multiple_inheritance_backward_reference(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case evaluates the functionality of register inheritance when multiple derived registers inherit
    from a base register via backward references. In this scenario, `RegisterA` is defined as the base register
    with a specific set of attributes, including fields. `RegisterB` inherits from `RegisterA`, and `RegisterC`
    subsequently inherits from `RegisterB`. This chain of backward references ensures that `RegisterC` ultimately
    inherits properties from `RegisterA` through `RegisterB`. The SVD file clearly defines the inheritance
    structure, allowing each derived register to have a distinct address offset while maintaining the core
    properties from the base register.

    **Expected Outcome:** The parser should correctly interpret the inheritance chain, ensuring that both `RegisterB`
    and `RegisterC` inherit all attributes from `RegisterA`. This means that `RegisterB` and `RegisterC` should
    have the same field (`FieldA` with bits 0 to 2) as defined in `RegisterA`. Each register should be positioned
    at their respective address offsets (`0x0` for `RegisterA`, `0x4` for `RegisterB`, and `0x8` for `RegisterC`)
    with a size of 32 bits. The parsing should be consistent with the expected behavior of `svdconv`, which
    handles such backward reference chains correctly.

    **Processable with svdconv:** yes
    """

    device = get_processed_device_from_testfile(
        "register_inheritance_via_derivedfrom/multiple_inheritance_backward_reference.svd"
    )

    assert len(device.peripherals) == 1
    assert len(device.peripherals[0].registers_clusters) == 3

    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 32
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2

    assert isinstance(device.peripherals[0].registers_clusters[1], Register)
    assert device.peripherals[0].registers_clusters[1].name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].address_offset == 0x4
    assert device.peripherals[0].registers_clusters[1].size == 32
    assert len(device.peripherals[0].registers_clusters[1].fields) == 1
    assert device.peripherals[0].registers_clusters[1].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[1].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[1].fields[0].msb == 2

    assert isinstance(device.peripherals[0].registers_clusters[2], Register)
    assert device.peripherals[0].registers_clusters[2].name == "RegisterC"
    assert device.peripherals[0].registers_clusters[2].address_offset == 0x8
    assert device.peripherals[0].registers_clusters[2].size == 32
    assert len(device.peripherals[0].registers_clusters[2].fields) == 1
    assert device.peripherals[0].registers_clusters[2].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[2].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[2].fields[0].msb == 2
SVD file: register_inheritance_via_derivedfrom/multiple_inheritance_backward_reference.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>multiple_inheritance_backward_reference</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <addressOffset>0x4</addressOffset>
        </register>
        <register derivedFrom="RegisterB">
          <name>RegisterC</name>
          <addressOffset>0x8</addressOffset>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_multiple_inheritance_forward_reference

This test case examines the scenario of register inheritance using forward references. Here, RegisterA is defined to inherit from RegisterB, which in turn is defined to inherit from RegisterC. The SVD file specifies these registers in a sequence where RegisterC is defined last, creating a chain of forward references. The objective is to verify if the parser can correctly resolve these references and apply the inheritance as intended. Each derived register should inherit properties from the subsequent one in the chain, even though they are defined in a forward manner.

Expected Outcome: The parser should successfully process the SVD file, correctly handling the forward references and applying the inheritance chain. This means that RegisterA should ultimately inherit properties from RegisterC via RegisterB, despite being defined earlier in the file. Each register should have the same field structure inherited from RegisterC, with FieldA occupying bits 0 to 2. The registers should appear at their respective address offsets: 0x0 for RegisterA, 0x4 for RegisterB, and 0x8 for RegisterC, all with a size of 32 bits. While svdconv does not handle such forward references, the parser should complete this without errors.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
@pytest.mark.filterwarnings("error::svdsuite.process.ProcessWarning")
def test_multiple_inheritance_forward_reference(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case examines the scenario of register inheritance using forward references. Here, `RegisterA` is
    defined to inherit from `RegisterB`, which in turn is defined to inherit from `RegisterC`. The SVD file
    specifies these registers in a sequence where `RegisterC` is defined last, creating a chain of forward
    references. The objective is to verify if the parser can correctly resolve these references and apply the
    inheritance as intended. Each derived register should inherit properties from the subsequent one in the chain,
    even though they are defined in a forward manner.

    **Expected Outcome:** The parser should successfully process the SVD file, correctly handling the forward
    references and applying the inheritance chain. This means that `RegisterA` should ultimately inherit
    properties from `RegisterC` via `RegisterB`, despite being defined earlier in the file. Each register should
    have the same field structure inherited from `RegisterC`, with `FieldA` occupying bits 0 to 2. The registers
    should appear at their respective address offsets: `0x0` for `RegisterA`, `0x4` for `RegisterB`, and `0x8` for
    `RegisterC`, all with a size of 32 bits. While `svdconv` does not handle such forward references, the parser
    should complete this without errors.

    **Processable with svdconv:** no
    """

    device = get_processed_device_from_testfile(
        "register_inheritance_via_derivedfrom/multiple_inheritance_forward_reference.svd"
    )

    assert len(device.peripherals) == 1
    assert len(device.peripherals[0].registers_clusters) == 3

    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 32
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2

    assert isinstance(device.peripherals[0].registers_clusters[1], Register)
    assert device.peripherals[0].registers_clusters[1].name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].address_offset == 0x4
    assert device.peripherals[0].registers_clusters[1].size == 32
    assert len(device.peripherals[0].registers_clusters[1].fields) == 1
    assert device.peripherals[0].registers_clusters[1].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[1].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[1].fields[0].msb == 2

    assert isinstance(device.peripherals[0].registers_clusters[2], Register)
    assert device.peripherals[0].registers_clusters[2].name == "RegisterC"
    assert device.peripherals[0].registers_clusters[2].address_offset == 0x8
    assert device.peripherals[0].registers_clusters[2].size == 32
    assert len(device.peripherals[0].registers_clusters[2].fields) == 1
    assert device.peripherals[0].registers_clusters[2].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[2].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[2].fields[0].msb == 2
SVD file: register_inheritance_via_derivedfrom/multiple_inheritance_forward_reference.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>multiple_inheritance_forward_reference</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register derivedFrom="RegisterB">
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
        </register>
        <register derivedFrom="RegisterC">
          <name>RegisterB</name>
          <addressOffset>0x4</addressOffset>
        </register>
        <register>
          <name>RegisterC</name>
          <addressOffset>0x8</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_override_behavior

This test case examines the use of the derivedFrom attribute to inherit properties from a base register while allowing for selective overrides. In this scenario, RegisterB is defined to inherit properties from RegisterA, but several attributes are explicitly overridden. The SVD file defines RegisterA with a comprehensive set of attributes, including size, access type, reset values, and field details. RegisterB inherits these attributes via derivedFrom, but overrides certain properties such as size, description, access type, and field structure.

Expected Outcome: The parser should correctly process RegisterB, inheriting all attributes from RegisterA except those that are explicitly overridden in RegisterB. This means that RegisterB should retain properties like alternateRegister, resetValue, and fields from RegisterA unless a different value is specified. For example, RegisterB should inherit the field FieldA from RegisterA but should also introduce a new field, FieldB. The parser should handle this inheritance and overriding mechanism seamlessly, producing a result where RegisterA and RegisterB are distinct yet connected through shared properties. This behavior matches the expected output from svdconv, which processes similar cases without issues.

Processable with svdconv: yes

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
@pytest.mark.filterwarnings("error::svdsuite.process.ProcessWarning")
def test_override_behavior(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case examines the use of the `derivedFrom` attribute to inherit properties from a base register
    while allowing for selective overrides. In this scenario, `RegisterB` is defined to inherit properties from
    `RegisterA`, but several attributes are explicitly overridden. The SVD file defines `RegisterA` with a
    comprehensive set of attributes, including size, access type, reset values, and field details. `RegisterB`
    inherits these attributes via `derivedFrom`, but overrides certain properties such as size, description,
    access type, and field structure.

    **Expected Outcome:** The parser should correctly process `RegisterB`, inheriting all attributes from `RegisterA`
    except those that are explicitly overridden in `RegisterB`. This means that `RegisterB` should retain
    properties like `alternateRegister`, `resetValue`, and `fields` from `RegisterA` unless a different value is
    specified. For example, `RegisterB` should inherit the field `FieldA` from `RegisterA` but should also
    introduce a new field, `FieldB`. The parser should handle this inheritance and overriding mechanism
    seamlessly, producing a result where `RegisterA` and `RegisterB` are distinct yet connected through shared
    properties. This behavior matches the expected output from `svdconv`, which processes similar cases without
    issues.

    **Processable with svdconv:** yes
    """

    device = get_processed_device_from_testfile("register_inheritance_via_derivedfrom/override_behavior.svd")

    assert len(device.peripherals) == 1
    assert len(device.peripherals[0].registers_clusters) == 2

    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].display_name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].description == "RegisterA description"
    assert device.peripherals[0].registers_clusters[0].alternate_register == "RegisterB"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 16
    assert device.peripherals[0].registers_clusters[0].access == AccessType.READ_ONLY
    assert device.peripherals[0].registers_clusters[0].protection == ProtectionStringType.SECURE
    assert device.peripherals[0].registers_clusters[0].reset_value == 0xDEAD
    assert device.peripherals[0].registers_clusters[0].reset_mask == 0xC0DE
    assert device.peripherals[0].registers_clusters[0].data_type == DataTypeType.UINT32_T
    assert device.peripherals[0].registers_clusters[0].modified_write_values == ModifiedWriteValuesType.ONE_TO_CLEAR
    assert device.peripherals[0].registers_clusters[0].write_constraint is not None
    assert device.peripherals[0].registers_clusters[0].write_constraint.write_as_read is True
    assert device.peripherals[0].registers_clusters[0].read_action == ReadActionType.MODIFY
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2
    assert device.peripherals[0].registers_clusters[0].fields[0].access == AccessType.READ_ONLY
    assert device.peripherals[0].registers_clusters[0].fields[0].write_constraint is not None
    assert device.peripherals[0].registers_clusters[0].fields[0].write_constraint.write_as_read is True

    assert isinstance(device.peripherals[0].registers_clusters[1], Register)
    assert device.peripherals[0].registers_clusters[1].name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].display_name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].description == "RegisterB description"
    assert device.peripherals[0].registers_clusters[1].alternate_register == "RegisterA"
    assert device.peripherals[0].registers_clusters[1].address_offset == 0x2
    assert device.peripherals[0].registers_clusters[1].size == 8
    assert device.peripherals[0].registers_clusters[1].access == AccessType.WRITE_ONLY
    assert device.peripherals[0].registers_clusters[1].protection == ProtectionStringType.NON_SECURE
    assert device.peripherals[0].registers_clusters[1].reset_value == 0xAB
    assert device.peripherals[0].registers_clusters[1].reset_mask == 0xDE
    assert device.peripherals[0].registers_clusters[1].data_type == DataTypeType.UINT8_T
    assert device.peripherals[0].registers_clusters[1].modified_write_values == ModifiedWriteValuesType.ONE_TO_SET
    assert device.peripherals[0].registers_clusters[1].write_constraint is not None
    assert device.peripherals[0].registers_clusters[1].write_constraint.use_enumerated_values is True
    assert device.peripherals[0].registers_clusters[1].read_action == ReadActionType.SET
    assert len(device.peripherals[0].registers_clusters[1].fields) == 2
    assert device.peripherals[0].registers_clusters[1].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[1].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[1].fields[0].msb == 2
    assert device.peripherals[0].registers_clusters[1].fields[0].access == AccessType.WRITE_ONLY
    assert device.peripherals[0].registers_clusters[1].fields[0].write_constraint is not None
    assert device.peripherals[0].registers_clusters[1].fields[0].write_constraint.use_enumerated_values is True
    assert device.peripherals[0].registers_clusters[1].fields[1].name == "FieldB"
    assert device.peripherals[0].registers_clusters[1].fields[1].lsb == 3
    assert device.peripherals[0].registers_clusters[1].fields[1].msb == 4
    assert device.peripherals[0].registers_clusters[1].fields[1].access == AccessType.WRITE_ONLY
    assert device.peripherals[0].registers_clusters[1].fields[1].write_constraint is not None
    assert device.peripherals[0].registers_clusters[1].fields[1].write_constraint.use_enumerated_values is True
SVD file: register_inheritance_via_derivedfrom/override_behavior.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>override_behavior</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <displayName>RegisterA</displayName>
          <description>RegisterA description</description>
          <alternateRegister>RegisterB</alternateRegister>
          <addressOffset>0x0</addressOffset>
          <size>16</size>
          <access>read-only</access>
          <protection>s</protection>
          <resetValue>0xDEAD</resetValue>
          <resetMask>0xC0DE</resetMask>
          <dataType>uint32_t</dataType>
          <modifiedWriteValues>oneToClear</modifiedWriteValues>
          <writeConstraint>
            <writeAsRead>true</writeAsRead>
          </writeConstraint>
          <readAction>modify</readAction>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <displayName>RegisterB</displayName>
          <description>RegisterB description</description>
          <alternateRegister>RegisterA</alternateRegister>
          <addressOffset>0x2</addressOffset>
          <size>8</size>
          <access>write-only</access>
          <protection>n</protection>
          <resetValue>0xAB</resetValue>
          <resetMask>0xDE</resetMask>
          <dataType>uint8_t</dataType>
          <modifiedWriteValues>oneToSet</modifiedWriteValues>
          <writeConstraint>
            <useEnumeratedValues>true</useEnumeratedValues>
          </writeConstraint>
          <readAction>set</readAction>
          <fields>
            <field>
              <name>FieldB</name>
              <bitOffset>3</bitOffset>
              <bitWidth>2</bitWidth>
            </field>
          </fields>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_register_overlap

This test case addresses a situation where two registers, RegisterA and RegisterB, have overlapping address spaces within the same peripheral. In this example, RegisterB is derived from RegisterA but is defined at an address offset (0x2) that causes it to overlap partially with RegisterA. While such overlaps can lead to conflicts, svdconv issues a warning rather than an error to maintain compatibility with older svdconv versions, which have not detected overlapping addresses. A robust parser implementation should mimic this behavior, issuing a warning to inform the user of the overlap but still proceed with processing the file.

Expected Outcome: The parser should successfully process the SVD file but issue a warning indicating the address overlap between RegisterA and RegisterB. This approach maintains compatibility with existing tools like svdconv, which handle such scenarios by warning the user rather than blocking the processing altogether.

Processable with svdconv: yes

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
def test_register_overlap(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case addresses a situation where two registers, `RegisterA` and `RegisterB`, have overlapping
    address spaces within the same peripheral. In this example, `RegisterB` is derived from `RegisterA` but is
    defined at an address offset (`0x2`) that causes it to overlap partially with `RegisterA`. While such overlaps
    can lead to conflicts, `svdconv` issues a warning rather than an error to maintain compatibility with older
    `svdconv` versions, which have not detected overlapping addresses. A robust parser implementation should mimic
    this behavior, issuing a warning to inform the user of the overlap but still proceed with processing the file.

    **Expected Outcome:** The parser should successfully process the SVD file but issue a warning indicating the
    address overlap between `RegisterA` and `RegisterB`. This approach maintains compatibility with existing tools
    like `svdconv`, which handle such scenarios by warning the user rather than blocking the processing
    altogether.

    **Processable with svdconv:** yes
    """

    with pytest.warns(ProcessWarning):
        device = get_processed_device_from_testfile("register_inheritance_via_derivedfrom/register_overlap.svd")

    assert len(device.peripherals) == 1
    assert len(device.peripherals[0].registers_clusters) == 2

    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 32
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2

    assert isinstance(device.peripherals[0].registers_clusters[1], Register)
    assert device.peripherals[0].registers_clusters[1].name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].address_offset == 0x2
    assert device.peripherals[0].registers_clusters[1].size == 16
    assert len(device.peripherals[0].registers_clusters[1].fields) == 1
    assert device.peripherals[0].registers_clusters[1].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[1].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[1].fields[0].msb == 2
SVD file: register_inheritance_via_derivedfrom/register_overlap.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>register_overlap</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <addressOffset>0x2</addressOffset>
          <size>16</size>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_same_address

This test case explores a scenario where two registers, RegisterA and RegisterB, share the same address offset within the same peripheral. The RegisterB is derived from RegisterA, meaning it inherits its configuration but is defined at the same address (0x0). According to the SVD standard, multiple registers should not occupy the same address space unless they have an alternate relationship, and svdconv enforces this rule by issuing an error. However, for enhanced compatibility, especially with older svdconv versions, it may be advisable to allow such configurations while issuing a warning instead of an outright error.

Expected Outcome: The parser should issue a warning indicating that RegisterA and RegisterB share the same address offset, but it should still successfully process the SVD file. This approach aligns with the idea of maintaining compatibility with various SVD formats, including older versions where multiple registers might share the same address. Although svdconv would reject this file outright, a more flexible parser should permit it while clearly warning users of the potential conflict.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
def test_same_address(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case explores a scenario where two registers, `RegisterA` and `RegisterB`, share the same address
    offset within the same peripheral. The `RegisterB` is derived from `RegisterA`, meaning it inherits its
    configuration but is defined at the same address (`0x0`). According to the SVD standard, multiple registers
    should not occupy the same address space unless they have an alternate relationship, and `svdconv` enforces
    this rule by issuing an error. However, for enhanced compatibility, especially with older `svdconv` versions,
    it may be advisable to allow such configurations while issuing a warning instead of an outright error.

    **Expected Outcome:** The parser should issue a warning indicating that `RegisterA` and `RegisterB` share the same
    address offset, but it should still successfully process the SVD file. This approach aligns with the idea of
    maintaining compatibility with various SVD formats, including older versions where multiple registers might
    share the same address. Although `svdconv` would reject this file outright, a more flexible parser should
    permit it while clearly warning users of the potential conflict.

    **Processable with svdconv:** no
    """

    with pytest.warns(ProcessWarning):
        device = get_processed_device_from_testfile("register_inheritance_via_derivedfrom/same_address.svd")

    assert len(device.peripherals) == 1
    assert len(device.peripherals[0].registers_clusters) == 2

    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 32
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2

    assert isinstance(device.peripherals[0].registers_clusters[1], Register)
    assert device.peripherals[0].registers_clusters[1].name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[1].size == 32
    assert len(device.peripherals[0].registers_clusters[1].fields) == 1
    assert device.peripherals[0].registers_clusters[1].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[1].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[1].fields[0].msb == 2
SVD file: register_inheritance_via_derivedfrom/same_address.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>same_address</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <addressOffset>0x0</addressOffset>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_simple_inheritance_backward_reference_different_scope

This test case evaluates the behavior of register inheritance using the derivedFrom attribute when the base register is defined within a different peripheral. In the SVD file, RegisterA is defined within PeripheralA, located at base address 0x40001000. This register contains a field named FieldA, occupying bits 0 through 2. In PeripheralB, which has a different base address (0x40002000), another RegisterA is defined that uses the derivedFrom attribute to inherit all properties from PeripheralA.RegisterA.

Expected Outcome: The parser should correctly process the SVD file, recognizing that PeripheralB.RegisterA inherits all attributes from PeripheralA.RegisterA, including the field definition FieldA. Both registers should have identical structures, with the derived register correctly inheriting the properties from its base, even though they are defined in separate peripherals. The parsing should be consistent with svdconv, which successfully handles this cross-scope backward reference, resulting in RegisterA in PeripheralB being properly inherited and recognized without issues.

Processable with svdconv: yes

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
@pytest.mark.filterwarnings("error::svdsuite.process.ProcessWarning")
def test_simple_inheritance_backward_reference_different_scope(
    get_processed_device_from_testfile: Callable[[str], Device]
):
    """
    This test case evaluates the behavior of register inheritance using the `derivedFrom` attribute when the base
    register is defined within a different peripheral. In the SVD file, `RegisterA` is defined within
    `PeripheralA`, located at base address `0x40001000`. This register contains a field named `FieldA`, occupying
    bits 0 through 2. In `PeripheralB`, which has a different base address (`0x40002000`), another `RegisterA` is
    defined that uses the `derivedFrom` attribute to inherit all properties from `PeripheralA.RegisterA`.

    **Expected Outcome:** The parser should correctly process the SVD file, recognizing that `PeripheralB.RegisterA`
    inherits all attributes from `PeripheralA.RegisterA`, including the field definition `FieldA`. Both registers
    should have identical structures, with the derived register correctly inheriting the properties from its base,
    even though they are defined in separate peripherals. The parsing should be consistent with `svdconv`, which
    successfully handles this cross-scope backward reference, resulting in `RegisterA` in `PeripheralB` being
    properly inherited and recognized without issues.

    **Processable with svdconv:** yes
    """

    device = get_processed_device_from_testfile(
        "register_inheritance_via_derivedfrom/simple_inheritance_backward_reference_different_scope.svd"
    )

    assert len(device.peripherals) == 2

    assert len(device.peripherals[0].registers_clusters) == 1
    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 32
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2

    assert len(device.peripherals[1].registers_clusters) == 1
    assert isinstance(device.peripherals[1].registers_clusters[0], Register)
    assert device.peripherals[1].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[1].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[1].registers_clusters[0].size == 32
    assert len(device.peripherals[1].registers_clusters[0].fields) == 1
    assert device.peripherals[1].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[1].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[1].registers_clusters[0].fields[0].msb == 2
SVD file: register_inheritance_via_derivedfrom/simple_inheritance_backward_reference_different_scope.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>simple_inheritance_backward_reference_different_scope</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
      </registers>
    </peripheral>
    <peripheral>
      <name>PeripheralB</name>
      <baseAddress>0x40002000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register derivedFrom="PeripheralA.RegisterA">
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_simple_inheritance_backward_reference_same_scope

This test case evaluates the behavior of register inheritance using the derivedFrom attribute within the same peripheral scope. The scenario involves RegisterB inheriting properties from RegisterA, which has been defined earlier in the same scope. In the provided SVD file, RegisterA is explicitly defined with an address offset of 0x0, and it contains a field named FieldA occupying bits 0 through 2. RegisterB is defined to inherit from RegisterA via the derivedFrom attribute, while being located at a different address offset (0x4).

Expected Outcome: The parser should successfully process the SVD file, recognizing RegisterB as inheriting all attributes from RegisterA. This includes the field FieldA with the same bit positioning (bits 0 to 2). RegisterA should appear at address offset 0x0 and RegisterB at 0x4, both having a size of 32 bits and containing an identical field structure. The parsing should complete without any issues, consistent with the expected behavior of svdconv, which correctly handles backward references within the same scope.

Processable with svdconv: yes

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@pytest.mark.filterwarnings("error::svdsuite.process.ProcessWarning")
def test_simple_inheritance_backward_reference_same_scope(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case evaluates the behavior of register inheritance using the `derivedFrom` attribute within the
    same peripheral scope. The scenario involves `RegisterB` inheriting properties from `RegisterA`, which has
    been defined earlier in the same scope. In the provided SVD file, `RegisterA` is explicitly defined with an
    address offset of `0x0`, and it contains a field named `FieldA` occupying bits 0 through 2. `RegisterB` is
    defined to inherit from `RegisterA` via the `derivedFrom` attribute, while being located at a different
    address offset (`0x4`).

    **Expected Outcome:** The parser should successfully process the SVD file, recognizing `RegisterB` as inheriting
    all attributes from `RegisterA`. This includes the field `FieldA` with the same bit positioning (bits 0 to 2).
    `RegisterA` should appear at address offset `0x0` and `RegisterB` at `0x4`, both having a size of 32 bits and
    containing an identical field structure. The parsing should complete without any issues, consistent with the
    expected behavior of `svdconv`, which correctly handles backward references within the same scope.

    **Processable with svdconv:** yes
    """

    device = get_processed_device_from_testfile(
        "register_inheritance_via_derivedfrom/simple_inheritance_backward_reference_same_scope.svd"
    )

    assert len(device.peripherals) == 1
    assert len(device.peripherals[0].registers_clusters) == 2

    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 32
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2

    assert isinstance(device.peripherals[0].registers_clusters[1], Register)
    assert device.peripherals[0].registers_clusters[1].name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].address_offset == 0x4
    assert device.peripherals[0].registers_clusters[1].size == 32
    assert len(device.peripherals[0].registers_clusters[1].fields) == 1
    assert device.peripherals[0].registers_clusters[1].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[1].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[1].fields[0].msb == 2
SVD file: register_inheritance_via_derivedfrom/simple_inheritance_backward_reference_same_scope.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>simple_inheritance_backward_reference_same_scope</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <addressOffset>0x4</addressOffset>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_simple_inheritance_forward_reference_different_scope

This test case explores the behavior of register inheritance using the derivedFrom attribute when a derived register attempts to inherit from a base register defined in a different peripheral that appears later in the file. Specifically, PeripheralA.RegisterA is set to inherit from PeripheralB.RegisterA, even though PeripheralB is defined after PeripheralA in the SVD file. The base register PeripheralB.RegisterA contains a field named FieldA located at bits 0 through 2, and it is defined at address offset 0x0 within PeripheralB.

Expected Outcome: The parser should be able to correctly handle this forward reference, recognizing that PeripheralA.RegisterA inherits all attributes from PeripheralB.RegisterA, including the field FieldA. Both registers should maintain identical structures, and the derived register should accurately reflect the inherited properties, despite the forward reference. Unlike svdconv, which cannot process this type of forward reference across different scopes and would produce an error, the parser is expected to resolve this relationship correctly, ensuring RegisterA in PeripheralA is properly inherited from PeripheralB.RegisterA without any issues.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
@pytest.mark.filterwarnings("error::svdsuite.process.ProcessWarning")
def test_simple_inheritance_forward_reference_different_scope(
    get_processed_device_from_testfile: Callable[[str], Device]
):
    """
    This test case explores the behavior of register inheritance using the `derivedFrom` attribute when a derived
    register attempts to inherit from a base register defined in a different peripheral that appears later in the
    file. Specifically, `PeripheralA.RegisterA` is set to inherit from `PeripheralB.RegisterA`, even though
    `PeripheralB` is defined after `PeripheralA` in the SVD file. The base register `PeripheralB.RegisterA`
    contains a field named `FieldA` located at bits 0 through 2, and it is defined at address offset `0x0` within
    `PeripheralB`.

    **Expected Outcome:** The parser should be able to correctly handle this forward reference, recognizing that
    `PeripheralA.RegisterA` inherits all attributes from `PeripheralB.RegisterA`, including the field `FieldA`.
    Both registers should maintain identical structures, and the derived register should accurately reflect the
    inherited properties, despite the forward reference. Unlike `svdconv`, which cannot process this type of
    forward reference across different scopes and would produce an error, the parser is expected to resolve this
    relationship correctly, ensuring `RegisterA` in `PeripheralA` is properly inherited from
    `PeripheralB.RegisterA` without any issues.

    **Processable with svdconv:** no
    """

    device = get_processed_device_from_testfile(
        "register_inheritance_via_derivedfrom/simple_inheritance_forward_reference_different_scope.svd"
    )

    assert len(device.peripherals) == 2

    assert len(device.peripherals[0].registers_clusters) == 1
    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 32
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2

    assert len(device.peripherals[1].registers_clusters) == 1
    assert isinstance(device.peripherals[1].registers_clusters[0], Register)
    assert device.peripherals[1].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[1].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[1].registers_clusters[0].size == 32
    assert len(device.peripherals[1].registers_clusters[0].fields) == 1
    assert device.peripherals[1].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[1].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[1].registers_clusters[0].fields[0].msb == 2
SVD file: register_inheritance_via_derivedfrom/simple_inheritance_forward_reference_different_scope.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>simple_inheritance_forward_reference_different_scope</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register derivedFrom="PeripheralB.RegisterA">
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
        </register>
      </registers>
    </peripheral>
    <peripheral>
      <name>PeripheralB</name>
      <baseAddress>0x40002000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_simple_inheritance_forward_reference_same_scope

This test case examines the handling of register inheritance using the derivedFrom attribute when the base register is defined later in the same peripheral scope. Here, RegisterA is defined to inherit from RegisterB, even though RegisterB appears afterward in the SVD file. This setup tests the parser's ability to resolve forward references, where the derived register (RegisterA) relies on properties that are specified only after its own definition. In the provided SVD file, RegisterA uses the derivedFrom attribute to inherit from RegisterB, which is defined with an address offset of 0x4 and contains a field named FieldA. RegisterA should inherit all properties of RegisterB, while occupying its own distinct address offset (0x0).

Expected Outcome: The parser should correctly handle the forward reference, resolving RegisterA's inheritance from RegisterB and applying all relevant properties. RegisterA should have the same field structure as RegisterB, including FieldA occupying bits 0 through 2. Both registers should be correctly recognized, with RegisterA located at address offset 0x0 and RegisterB at 0x4, each with a size of 32 bits. Unlike svdconv, which cannot handle forward references and raises an error, the parser should resolve this scenario seamlessly.

Processable with svdconv: no

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
@pytest.mark.filterwarnings("error::svdsuite.process.ProcessWarning")
def test_simple_inheritance_forward_reference_same_scope(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case examines the handling of register inheritance using the `derivedFrom` attribute when the base
    register is defined later in the same peripheral scope. Here, `RegisterA` is defined to inherit from
    `RegisterB`, even though `RegisterB` appears afterward in the SVD file. This setup tests the parser's ability
    to resolve forward references, where the derived register (`RegisterA`) relies on properties that are
    specified only after its own definition. In the provided SVD file, `RegisterA` uses the `derivedFrom`
    attribute to inherit from `RegisterB`, which is defined with an address offset of `0x4` and contains a field
    named `FieldA`. `RegisterA` should inherit all properties of `RegisterB`, while occupying its own distinct
    address offset (`0x0`).

    **Expected Outcome:** The parser should correctly handle the forward reference, resolving `RegisterA`'s
    inheritance from `RegisterB` and applying all relevant properties. `RegisterA` should have the same field
    structure as `RegisterB`, including `FieldA` occupying bits 0 through 2. Both registers should be correctly
    recognized, with `RegisterA` located at address offset `0x0` and `RegisterB` at `0x4`, each with a size of 32
    bits. Unlike `svdconv`, which cannot handle forward references and raises an error, the parser should resolve
    this scenario seamlessly.

    **Processable with svdconv:** no
    """

    device = get_processed_device_from_testfile(
        "register_inheritance_via_derivedfrom/simple_inheritance_forward_reference_same_scope.svd"
    )

    assert len(device.peripherals) == 1
    assert len(device.peripherals[0].registers_clusters) == 2

    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 32
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2

    assert isinstance(device.peripherals[0].registers_clusters[1], Register)
    assert device.peripherals[0].registers_clusters[1].name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].address_offset == 0x4
    assert device.peripherals[0].registers_clusters[1].size == 32
    assert len(device.peripherals[0].registers_clusters[1].fields) == 1
    assert device.peripherals[0].registers_clusters[1].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[1].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[1].fields[0].msb == 2
SVD file: register_inheritance_via_derivedfrom/simple_inheritance_forward_reference_same_scope.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>simple_inheritance_forward_reference_same_scope</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register derivedFrom="RegisterB">
          <name>RegisterA</name>
          <addressOffset>0x0</addressOffset>
        </register>
        <register>
          <name>RegisterB</name>
          <addressOffset>0x4</addressOffset>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>

test_value_inheritance

This test case examines how the derivedFrom attribute is used to inherit register properties, focusing on a scenario where RegisterB inherits multiple attributes from RegisterA. In the provided SVD file, RegisterA is defined with a wide range of attributes, including display name, description, access type, size, protection level, and more. RegisterB is set to inherit from RegisterA while having a distinct address offset of 0x2. The test ensures that RegisterB correctly inherits all properties of RegisterA except for the explicitly overridden attributes. A special case is the attribute displayName. Although it is also inherited, it is only allowed to appear once within the scope. Therefore, it must be explicitly overridden in RegisterB.

Expected Outcome: The parser should successfully process the SVD file and recognize that RegisterB inherits all applicable properties from RegisterA. This includes attributes such as the display name, description, size, access type, and protection level, among others. RegisterA should be located at address offset 0x0, while RegisterB should be at 0x2, both with the same attributes and configurations. The inherited properties should match precisely, reflecting accurate inheritance behavior. This is consistent with svdconv, which also handles this scenario correctly without any issues.

Processable with svdconv: yes

Source code in tests/test_process/test_register_inheritance_via_derived_from.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
@pytest.mark.filterwarnings("error::svdsuite.process.ProcessWarning")
def test_value_inheritance(get_processed_device_from_testfile: Callable[[str], Device]):
    """
    This test case examines how the `derivedFrom` attribute is used to inherit register properties, focusing on a
    scenario where `RegisterB` inherits multiple attributes from `RegisterA`. In the provided SVD file,
    `RegisterA` is defined with a wide range of attributes, including display name, description, access type,
    size, protection level, and more. `RegisterB` is set to inherit from `RegisterA` while having a distinct
    address offset of `0x2`. The test ensures that `RegisterB` correctly inherits all properties of `RegisterA`
    except for the explicitly overridden attributes. A special case is the attribute `displayName`. Although it is
    also inherited, it is only allowed to appear once within the scope. Therefore, it must be explicitly
    overridden in `RegisterB`.

    **Expected Outcome:** The parser should successfully process the SVD file and recognize that `RegisterB` inherits
    all applicable properties from `RegisterA`. This includes attributes such as the display name, description,
    size, access type, and protection level, among others. `RegisterA` should be located at address offset `0x0`,
    while `RegisterB` should be at `0x2`, both with the same attributes and configurations. The inherited
    properties should match precisely, reflecting accurate inheritance behavior. This is consistent with
    `svdconv`, which also handles this scenario correctly without any issues.

    **Processable with svdconv:** yes
    """

    device = get_processed_device_from_testfile("register_inheritance_via_derivedfrom/value_inheritance.svd")

    assert len(device.peripherals) == 1
    assert len(device.peripherals[0].registers_clusters) == 2

    assert isinstance(device.peripherals[0].registers_clusters[0], Register)
    assert device.peripherals[0].registers_clusters[0].name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].display_name == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].description == "RegisterA description"
    assert device.peripherals[0].registers_clusters[0].alternate_register == "RegisterA"
    assert device.peripherals[0].registers_clusters[0].address_offset == 0x0
    assert device.peripherals[0].registers_clusters[0].size == 16
    assert device.peripherals[0].registers_clusters[0].access == AccessType.READ_ONLY
    assert device.peripherals[0].registers_clusters[0].protection == ProtectionStringType.SECURE
    assert device.peripherals[0].registers_clusters[0].reset_value == 0xDEAD
    assert device.peripherals[0].registers_clusters[0].reset_mask == 0xC0DE
    assert device.peripherals[0].registers_clusters[0].data_type == DataTypeType.UINT32_T
    assert device.peripherals[0].registers_clusters[0].modified_write_values == ModifiedWriteValuesType.ONE_TO_CLEAR
    assert device.peripherals[0].registers_clusters[0].write_constraint is not None
    assert device.peripherals[0].registers_clusters[0].write_constraint.write_as_read is True
    assert device.peripherals[0].registers_clusters[0].read_action == ReadActionType.MODIFY
    assert len(device.peripherals[0].registers_clusters[0].fields) == 1
    assert device.peripherals[0].registers_clusters[0].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[0].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[0].fields[0].msb == 2
    assert device.peripherals[0].registers_clusters[0].fields[0].access == AccessType.READ_ONLY
    assert device.peripherals[0].registers_clusters[0].fields[0].write_constraint is not None
    assert device.peripherals[0].registers_clusters[0].fields[0].write_constraint.write_as_read is True

    assert isinstance(device.peripherals[0].registers_clusters[1], Register)
    assert device.peripherals[0].registers_clusters[1].name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].display_name == "RegisterB"
    assert device.peripherals[0].registers_clusters[1].description == "RegisterA description"
    assert device.peripherals[0].registers_clusters[1].alternate_register == "RegisterA"
    assert device.peripherals[0].registers_clusters[1].address_offset == 0x2
    assert device.peripherals[0].registers_clusters[1].size == 16
    assert device.peripherals[0].registers_clusters[1].access == AccessType.READ_ONLY
    assert device.peripherals[0].registers_clusters[1].protection == ProtectionStringType.SECURE
    assert device.peripherals[0].registers_clusters[1].reset_value == 0xDEAD
    assert device.peripherals[0].registers_clusters[1].reset_mask == 0xC0DE
    assert device.peripherals[0].registers_clusters[1].data_type == DataTypeType.UINT32_T
    assert device.peripherals[0].registers_clusters[1].modified_write_values == ModifiedWriteValuesType.ONE_TO_CLEAR
    assert device.peripherals[0].registers_clusters[1].write_constraint is not None
    assert device.peripherals[0].registers_clusters[1].write_constraint.write_as_read is True
    assert device.peripherals[0].registers_clusters[1].read_action == ReadActionType.MODIFY
    assert len(device.peripherals[0].registers_clusters[1].fields) == 1
    assert device.peripherals[0].registers_clusters[1].fields[0].name == "FieldA"
    assert device.peripherals[0].registers_clusters[1].fields[0].lsb == 0
    assert device.peripherals[0].registers_clusters[1].fields[0].msb == 2
    assert device.peripherals[0].registers_clusters[1].fields[0].access == AccessType.READ_ONLY
    assert device.peripherals[0].registers_clusters[1].fields[0].write_constraint is not None
    assert device.peripherals[0].registers_clusters[1].fields[0].write_constraint.write_as_read is True
SVD file: register_inheritance_via_derivedfrom/value_inheritance.svd
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?xml version='1.0' encoding='utf-8'?>
<device xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" schemaVersion="1.3">
  <name>value_inheritance</name>
  <version>1.0</version>
  <description>Test_Example device</description>
  <cpu>
  <name>CM0</name>
  <revision>r0p0</revision>
  <endian>little</endian>
  <mpuPresent>false</mpuPresent>
  <fpuPresent>false</fpuPresent>
  <nvicPrioBits>4</nvicPrioBits>
  <vendorSystickConfig>false</vendorSystickConfig>
  </cpu>
  <addressUnitBits>8</addressUnitBits>
  <width>32</width>
  <peripherals>
    <peripheral>
      <name>PeripheralA</name>
      <baseAddress>0x40001000</baseAddress>
      <addressBlock>
        <offset>0x0</offset>
        <size>0x1000</size>
        <usage>registers</usage>
      </addressBlock>
      <registers>
        <register>
          <name>RegisterA</name>
          <displayName>RegisterA</displayName>
          <description>RegisterA description</description>
          <alternateRegister>RegisterA</alternateRegister>
          <addressOffset>0x0</addressOffset>
          <size>16</size>
          <access>read-only</access>
          <protection>s</protection>
          <resetValue>0xDEAD</resetValue>
          <resetMask>0xC0DE</resetMask>
          <dataType>uint32_t</dataType>
          <modifiedWriteValues>oneToClear</modifiedWriteValues>
          <writeConstraint>
            <writeAsRead>true</writeAsRead>
          </writeConstraint>
          <readAction>modify</readAction>
          <fields>
            <field>
              <name>FieldA</name>
              <bitOffset>0</bitOffset>
              <bitWidth>3</bitWidth>
            </field>
          </fields>
        </register>
        <register derivedFrom="RegisterA">
          <name>RegisterB</name>
          <displayName>RegisterB</displayName>
          <addressOffset>0x2</addressOffset>
        </register>
      </registers>
    </peripheral>
  </peripherals>
</device>