You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RFC #30: Address feedback from the 2023-11-20 Amaranth meeting.
- clarify how Signature subclasses can have multiple annotations.
- add a naming policy for annotations.
- rename lib.annotation to lib.meta.
- remove mention that ComponentMetadata inherits from Annotation.
- expand drawbacks and rationale sections.
- move support for clock and reset signals to a later RFC.
Copy file name to clipboardExpand all lines: text/0000-component-metadata.md
+40-27Lines changed: 40 additions & 27 deletions
Original file line number
Diff line number
Diff line change
@@ -30,7 +30,9 @@ This RFC proposes a JSON-based format to describe and exchange component metadat
30
30
31
31
### Component metadata
32
32
33
-
An `amaranth.lib.wiring.Component` can provide metadata about itself, represented as a JSON object. This metadata contains a hierarchical description of every port of its interface:
33
+
An `amaranth.lib.wiring.Component` can provide metadata about itself, represented as a JSON object. This metadata contains a hierarchical description of every port of its interface.
34
+
35
+
The following example defines an `AsyncSerial` component, and outputs its metadata:
34
36
35
37
```python3
36
38
from amaranth import*
@@ -179,14 +181,14 @@ The `["interface"]["annotations"]` object, which is empty here, is explained in
179
181
180
182
Users can attach arbitrary annotations to an `amaranth.lib.wiring.Signature`, which are automatically collected into the metadata of components using this signature.
181
183
182
-
An `Annotation` class has a name (e.g. `"org.amaranth-lang.soc.memory-map"`) and a [JSON schema](https://json-schema.org) defining the structure of its instances. To continue our previous example, we add an annotation to `AsyncSerialSignature` that will allow us to describe a [8-N-1](https://en.wikipedia.org/wiki/8-N-1) configuration:
184
+
An `Annotation` class has a name (e.g. `"org.amaranth-lang.soc.memory-map"`) and a [JSON schema](https://json-schema.org) defining the structure of its instances. To continue our `AsyncSerial` example, we add an annotation to `AsyncSerialSignature` that will allow us to describe a [8-N-1](https://en.wikipedia.org/wiki/8-N-1) configuration:
Note: `Signature.annotations` can return multiple annotations, but they must have different names.
232
-
233
-
Printing ``json.dumps(serial.metadata.as_json(), indent=4)`` will now output this:
233
+
The JSON object returned by ``serial.metadata.as_json()`` will now use this annotation:
234
234
235
235
```json
236
236
{
@@ -318,7 +318,7 @@ Printing ``json.dumps(serial.metadata.as_json(), indent=4)`` will now output thi
318
318
}
319
319
},
320
320
"annotations": {
321
-
"org.example.serial": {
321
+
"com.example.serial": {
322
322
"data_bits": 8,
323
323
"parity": "none"
324
324
}
@@ -327,14 +327,28 @@ Printing ``json.dumps(serial.metadata.as_json(), indent=4)`` will now output thi
327
327
}
328
328
```
329
329
330
+
#### Annotation names and schema URLs
331
+
332
+
Annotation names must be prefixed by a reversed second-level domain name (e.g. "com.example") that belongs to the person or entity defining the annotation. Annotation names are obtainable from their schema URL (provided by the `"$id"` key of `Annotation.schema`). To ensure this, schema URLs must have the following structure: `"<protocol>://<domain>/schema/<version>/<path>"`. The version of an annotation schema should match the Python package that implements it.
333
+
334
+
Some examples of valid schema URLs:
335
+
336
+
- "https://example.com/schema/1.0/serial" for the "com.example.serial" annotation;
337
+
- "https://amaranth-lang.org/schema/0.4/fifo" for "org.amaranth-lang.fifo";
338
+
- "https://amaranth-lang.org/schema/0.1/soc/memory-map" for "org.amaranth-lang.soc.memory-map".
- add an `Annotation` base class to `amaranth.lib.annotations`, with:
345
+
- add an `Annotation` base class to `amaranth.lib.meta`, with:
336
346
* a `.name` "abstract" class attribute, which must be a string (e.g. "org.amaranth-lang.soc.memory-map").
337
347
* a `.schema` "abstract" class attribute, which must be a JSON schema, as a dict.
348
+
* a `.__init_subclass__()` class method, which raises an exception if:
349
+
-`.schema` does not comply with the [2020-12 draft](https://json-schema.org/specification-links#2020-12) of the JSON Schema specification.
350
+
-`.name` cannot be extracted from the `.schema["$id"]` URL (as explained [here](#annotation-names-and-schema-urls)).
351
+
- a `.origin` attribute, which returns the Python object described by an annotation instance.
338
352
* a `.validate()` class method, which takes a JSON instance as argument. An exception is raised if the instance does not comply with the schema.
339
353
* a `.as_json()` abstract method, which must return a JSON instance, as a dict. This instance must be compliant with `.schema`, i.e. `self.validate(self.as_json())` must succeed.
340
354
@@ -344,12 +358,13 @@ The following changes are made to `amaranth.lib.wiring`:
344
358
### Component metadata
345
359
346
360
The following changes are made to `amaranth.lib.wiring`:
347
-
- add a `ComponentMetadata` class, inheriting from `Annotation`, where:
348
-
-`.name` returns "org.amaranth-lang.component".
349
-
-`.schema` returns a JSON schema describing component metadata. Its definition is detailed below.
361
+
- add a `ComponentMetadata` class, with:
362
+
- a `.name` class attribute, which returns `"org.amaranth-lang.component"`.
363
+
- a `.schema` class attribute, which returns a JSON schema of component metadata. Its definition is detailed [below](#component-metadata-schema).
364
+
- a `.validate()` class method, which takes a JSON instance as argument. An exception is raised if the instance does not comply with the schema.
350
365
-`.__init__()` takes a `Component` object as parameter.
351
-
-`.origin` returns the component object given in `.__init__()`.
352
-
-`.as_json()` returns a JSON instance of `.origin`, that complies with `.schema`. It is populated by iterating over the component's interface and annotations.
366
+
- a `.origin` attribute, which returns the component object given in `.__init__()`.
367
+
-a `.as_json()`method, which returns a JSON instance of `.origin` that complies with `.schema`. It is populated by iterating over the component's interface and annotations.
353
368
- add a `.metadata` property to `Component`, which returns `ComponentMetadata(self)`.
354
369
355
370
#### Component metadata schema
@@ -449,32 +464,30 @@ class ComponentMetadata(Annotation):
449
464
# ...
450
465
```
451
466
452
-
Notes:
453
-
- Reset values are represented by their two's complement. For example, the reset value of `Member(Out, signed(2), reset=-1)` would be given as `3`.
454
-
- Despite not being enforced in this schema, annotations must be uniquely identified by their name. For example, an `"org.example.serial"` annotation may have only one possible schema.
467
+
Reset values are represented by their two's complement. For example, the reset value of `Member(Out, signed(2), reset=-1)` would be given as `3`.
455
468
456
469
## Drawbacks
457
470
[drawbacks]: #drawbacks
458
471
459
-
-`Annotation` class definitions must be kept in sync with their associated `Signature`. Using `Annotation.validate()` can catch some mismatches, but won't help if one forgets to add a new attribute to the JSON schema.
460
-
- it is possible to define multiple `Annotation` classes with the same `.name` attribute.
472
+
- Developers need to learn the JSON Schema language to define annotations.
473
+
- An annotation schema URL may point to a non-existent domain, despite being well formatted.
474
+
- Handling backward-incompatible changes in new versions of an annotation is left to its consumers.
- As an alternative, do nothing; let tools and downstream libraries provide non-interoperable mechanisms to introspect components to and from Amaranth designs.
465
480
- Usage of this feature is entirely optional. It has a limited impact on the `amaranth.lib.wiring`, by reserving only two attributes: `Signature.annotations` and `Component.metadata`.
466
481
- JSON schema is an IETF standard that is well supported across tools and programming languages.
482
+
- This metadata format can be translated into other formats, such as [IP-XACT](https://www.accellera.org/downloads/standards/ip-xact).
467
483
468
484
## Unresolved questions
469
485
[unresolved-questions]: #unresolved-questions
470
486
471
-
To do before merging:
472
-
- Add support for clock and reset ports of a component.
473
-
474
-
Out of scope:
475
-
- Add support for port annotations (e.g. to describe non-trivial shapes).
487
+
- The clock and reset ports of a component are omitted from this metadata format. Currently, the clock domains of an Amaranth component are only known at elaboration, whereas this RFC requires metadata to be accessible at any time. While this is a significant limitation for multi-clock mixed HDL designs, single-clock designs may be assumed to have a positive edge clock `"clk"` and a synchronous reset `"rst"`. Support for arbitrary clock domains should be introduced in later RFCs.
488
+
- Annotating individual ports of an interface is not out of the scope of this RFC. Port annotations may be useful to describe non-trivial signal shapes, and introduced in a later RFC.
476
489
477
490
## Future possibilities
478
491
[future-possibilities]: #future-possibilities
479
492
480
-
While this RFC can apply to any Amaranth component, one of its motivating use cases is the ability to export the interface and behavioral properties of SoC peripherals.
493
+
While this RFC can apply to any Amaranth component, one of its motivating use cases is the ability to export the interface and behavioral properties of SoC peripherals in various formats, such as SVD.
0 commit comments