lib.data: add reference documentation.
This commit is contained in:
parent
a5ffa38e64
commit
68e292c681
10 changed files with 792 additions and 10 deletions
|
|
@ -25,10 +25,12 @@ While code that uses the features listed as deprecated below will work in Amaran
|
|||
Implemented RFCs
|
||||
----------------
|
||||
|
||||
.. _RFC 1: https://amaranth-lang.org/rfcs/0001-aggregate-data-structures.html
|
||||
.. _RFC 3: https://amaranth-lang.org/rfcs/0003-enumeration-shapes.html
|
||||
.. _RFC 4: https://amaranth-lang.org/rfcs/0004-const-castable-exprs.html
|
||||
.. _RFC 5: https://amaranth-lang.org/rfcs/0005-remove-const-normalize.html
|
||||
|
||||
* `RFC 1`_: Aggregate data structure library
|
||||
* `RFC 3`_: Enumeration shapes
|
||||
* `RFC 4`_: Constant-castable expressions
|
||||
* `RFC 5`_: Remove Const.normalize
|
||||
|
|
@ -46,7 +48,7 @@ Language changes
|
|||
* Changed: :meth:`Value.cast` casts :class:`ValueCastable` objects recursively.
|
||||
* Changed: :meth:`Value.cast` treats instances of classes derived from both :class:`enum.Enum` and :class:`int` (including :class:`enum.IntEnum`) as enumerations rather than integers.
|
||||
* Changed: :meth:`Value.matches` with an empty list of patterns returns ``Const(1)`` rather than ``Const(0)``, to match the behavior of ``with m.Case():``.
|
||||
* Changed: :class:`Cat` warns if an enumeration without an explicitly specified shape is used.
|
||||
* Changed: :class:`Cat` warns if an enumeration without an explicitly specified shape is used. (`RFC 3`_)
|
||||
* Deprecated: :meth:`Const.normalize`. (`RFC 5`_)
|
||||
* Removed: (deprecated in 0.1) casting of :class:`Shape` to and from a ``(width, signed)`` tuple.
|
||||
* Removed: (deprecated in 0.3) :class:`ast.UserValue`.
|
||||
|
|
@ -58,7 +60,8 @@ Standard library changes
|
|||
|
||||
.. currentmodule:: amaranth.lib
|
||||
|
||||
* Added: :mod:`amaranth.lib.enum`.
|
||||
* Added: :mod:`amaranth.lib.enum`. (`RFC 3`_)
|
||||
* Added: :mod:`amaranth.lib.data`. (`RFC 1`_)
|
||||
|
||||
|
||||
Toolchain changes
|
||||
|
|
|
|||
|
|
@ -414,6 +414,14 @@ Signals assigned in a :ref:`combinatorial <lang-comb>` domain are not affected b
|
|||
True
|
||||
|
||||
|
||||
.. _lang-data:
|
||||
|
||||
Data structures
|
||||
===============
|
||||
|
||||
Amaranth provides aggregate data structures in the standard library module :mod:`amaranth.lib.data`.
|
||||
|
||||
|
||||
.. _lang-operators:
|
||||
|
||||
Operators
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Standard library
|
|||
:maxdepth: 2
|
||||
|
||||
stdlib/enum
|
||||
stdlib/data
|
||||
stdlib/coding
|
||||
stdlib/cdc
|
||||
stdlib/fifo
|
||||
|
|
|
|||
21
docs/stdlib/_images/data/array_layout.svg
Normal file
21
docs/stdlib/_images/data/array_layout.svg
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<!--
|
||||
Render the following with wavedrom-bitfield:
|
||||
|
||||
{
|
||||
"reg": [
|
||||
{"name": "[0]", "bits": 4},
|
||||
{"name": "[1]", "bits": 4},
|
||||
{"name": "[2]", "bits": 4},
|
||||
{"name": "[3]", "bits": 4},
|
||||
],
|
||||
"config": {
|
||||
"lanes": 1,
|
||||
"compact": true,
|
||||
"vflip": true,
|
||||
"hspace": 650
|
||||
}
|
||||
}
|
||||
|
||||
Then add 14 to height and viewBox.height.
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="650" height="70" viewBox="0 0 650 70" class="WaveDrom"><g transform="translate(0.5,0.5)" text-anchor="middle" font-size="14" font-family="sans-serif" font-weight="normal"><g transform="translate(4,21)"><g stroke="black" stroke-width="1" stroke-linecap="round"><line x2="641"></line><line x1="641" x2="641" y2="31"></line><line x2="641" y1="31" y2="31"></line><line y2="31"></line><line x1="40" x2="40" y2="3"></line><line x1="40" x2="40" y1="31" y2="28"></line><line x1="80" x2="80" y2="3"></line><line x1="80" x2="80" y1="31" y2="28"></line><line x1="120" x2="120" y2="3"></line><line x1="120" x2="120" y1="31" y2="28"></line><line x1="160" x2="160" y2="31"></line><line x1="200" x2="200" y2="3"></line><line x1="200" x2="200" y1="31" y2="28"></line><line x1="240" x2="240" y2="3"></line><line x1="240" x2="240" y1="31" y2="28"></line><line x1="280" x2="280" y2="3"></line><line x1="280" x2="280" y1="31" y2="28"></line><line x1="321" x2="321" y2="31"></line><line x1="361" x2="361" y2="3"></line><line x1="361" x2="361" y1="31" y2="28"></line><line x1="401" x2="401" y2="3"></line><line x1="401" x2="401" y1="31" y2="28"></line><line x1="441" x2="441" y2="3"></line><line x1="441" x2="441" y1="31" y2="28"></line><line x1="481" x2="481" y2="31"></line><line x1="521" x2="521" y2="3"></line><line x1="521" x2="521" y1="31" y2="28"></line><line x1="561" x2="561" y2="3"></line><line x1="561" x2="561" y1="31" y2="28"></line><line x1="601" x2="601" y2="3"></line><line x1="601" x2="601" y1="31" y2="28"></line></g><g><g></g><g transform="translate(20,-11)"></g><g transform="translate(20,15)"><g transform="translate(60)"><text y="6"><tspan>[0]</tspan></text></g><g transform="translate(220)"><text y="6"><tspan>[1]</tspan></text></g><g transform="translate(381)"><text y="6"><tspan>[2]</tspan></text></g><g transform="translate(541)"><text y="6"><tspan>[3]</tspan></text></g></g><g transform="translate(20,39)"></g></g></g><g transform="translate(4,-3)"><g transform="translate(20,11)"><text y="6">0</text></g><g transform="translate(140,11)"><text y="6">3</text></g><g transform="translate(180,11)"><text y="6">4</text></g><g transform="translate(300,11)"><text y="6">7</text></g><g transform="translate(341,11)"><text y="6">8</text></g><g transform="translate(461,11)"><text y="6">11</text></g><g transform="translate(501,11)"><text y="6">12</text></g><g transform="translate(621,11)"><text y="6">15</text></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
27
docs/stdlib/_images/data/flexible_layout.svg
Normal file
27
docs/stdlib/_images/data/flexible_layout.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.7 KiB |
18
docs/stdlib/_images/data/rgb565_layout.svg
Normal file
18
docs/stdlib/_images/data/rgb565_layout.svg
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!--
|
||||
Render the following with wavedrom-bitfield:
|
||||
|
||||
{
|
||||
"reg": [
|
||||
{"name": ".red", "bits": 5, type: 2},
|
||||
{"name": ".green", "bits": 6, type: 3},
|
||||
{"name": ".blue", "bits": 5, type: 4}
|
||||
],
|
||||
"config": {
|
||||
"lanes": 1,
|
||||
"compact": true,
|
||||
"vflip": true,
|
||||
"hspace": 650
|
||||
}
|
||||
}
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="650" height="56" viewBox="0 0 650 56" class="WaveDrom"><g transform="translate(0.5,0.5)" text-anchor="middle" font-size="14" font-family="sans-serif" font-weight="normal"><g transform="translate(4,21)"><g stroke="black" stroke-width="1" stroke-linecap="round"><line x2="641"></line><line x1="641" x2="641" y2="31"></line><line x2="641" y1="31" y2="31"></line><line y2="31"></line><line x1="40" x2="40" y2="3"></line><line x1="40" x2="40" y1="31" y2="28"></line><line x1="80" x2="80" y2="3"></line><line x1="80" x2="80" y1="31" y2="28"></line><line x1="120" x2="120" y2="3"></line><line x1="120" x2="120" y1="31" y2="28"></line><line x1="160" x2="160" y2="3"></line><line x1="160" x2="160" y1="31" y2="28"></line><line x1="200" x2="200" y2="31"></line><line x1="240" x2="240" y2="3"></line><line x1="240" x2="240" y1="31" y2="28"></line><line x1="280" x2="280" y2="3"></line><line x1="280" x2="280" y1="31" y2="28"></line><line x1="321" x2="321" y2="3"></line><line x1="321" x2="321" y1="31" y2="28"></line><line x1="361" x2="361" y2="3"></line><line x1="361" x2="361" y1="31" y2="28"></line><line x1="401" x2="401" y2="3"></line><line x1="401" x2="401" y1="31" y2="28"></line><line x1="441" x2="441" y2="31"></line><line x1="481" x2="481" y2="3"></line><line x1="481" x2="481" y1="31" y2="28"></line><line x1="521" x2="521" y2="3"></line><line x1="521" x2="521" y1="31" y2="28"></line><line x1="561" x2="561" y2="3"></line><line x1="561" x2="561" y1="31" y2="28"></line><line x1="601" x2="601" y2="3"></line><line x1="601" x2="601" y1="31" y2="28"></line></g><g><g><rect width="200" height="31" field=".red" style="fill-opacity:0.1;fill:hsl(0,100%,50%)"></rect><rect x="200" width="240" height="31" field=".green" style="fill-opacity:0.1;fill:hsl(80,100%,50%)"></rect><rect x="441" width="200" height="31" field=".blue" style="fill-opacity:0.1;fill:hsl(170,100%,50%)"></rect></g><g transform="translate(20,-11)"></g><g transform="translate(20,15)"><g transform="translate(80)"><text y="6"><tspan>.red</tspan></text></g><g transform="translate(300)"><text y="6"><tspan>.green</tspan></text></g><g transform="translate(521)"><text y="6"><tspan>.blue</tspan></text></g></g><g transform="translate(20,39)"></g></g></g><g transform="translate(4,-3)"><g transform="translate(20,11)"><text y="6">0</text></g><g transform="translate(180,11)"><text y="6">4</text></g><g transform="translate(220,11)"><text y="6">5</text></g><g transform="translate(421,11)"><text y="6">10</text></g><g transform="translate(461,11)"><text y="6">11</text></g><g transform="translate(621,11)"><text y="6">15</text></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
20
docs/stdlib/_images/data/struct_layout.svg
Normal file
20
docs/stdlib/_images/data/struct_layout.svg
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!--
|
||||
Render the following with wavedrom-bitfield:
|
||||
|
||||
{
|
||||
"reg": [
|
||||
{"name": ".first", "bits": 3},
|
||||
{"name": ".second", "bits": 7},
|
||||
{"name": ".third", "bits": 6}
|
||||
],
|
||||
"config": {
|
||||
"lanes": 1,
|
||||
"compact": true,
|
||||
"vflip": true,
|
||||
"hspace": 650
|
||||
}
|
||||
}
|
||||
|
||||
Then add 14 to height and viewBox.height.
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="650" height="70" viewBox="0 0 650 70" class="WaveDrom"><g transform="translate(0.5,0.5)" text-anchor="middle" font-size="14" font-family="sans-serif" font-weight="normal"><g transform="translate(4,21)"><g stroke="black" stroke-width="1" stroke-linecap="round"><line x2="641"></line><line x1="641" x2="641" y2="31"></line><line x2="641" y1="31" y2="31"></line><line y2="31"></line><line x1="40" x2="40" y2="3"></line><line x1="40" x2="40" y1="31" y2="28"></line><line x1="80" x2="80" y2="3"></line><line x1="80" x2="80" y1="31" y2="28"></line><line x1="120" x2="120" y2="31"></line><line x1="160" x2="160" y2="3"></line><line x1="160" x2="160" y1="31" y2="28"></line><line x1="200" x2="200" y2="3"></line><line x1="200" x2="200" y1="31" y2="28"></line><line x1="240" x2="240" y2="3"></line><line x1="240" x2="240" y1="31" y2="28"></line><line x1="280" x2="280" y2="3"></line><line x1="280" x2="280" y1="31" y2="28"></line><line x1="321" x2="321" y2="3"></line><line x1="321" x2="321" y1="31" y2="28"></line><line x1="361" x2="361" y2="3"></line><line x1="361" x2="361" y1="31" y2="28"></line><line x1="401" x2="401" y2="31"></line><line x1="441" x2="441" y2="3"></line><line x1="441" x2="441" y1="31" y2="28"></line><line x1="481" x2="481" y2="3"></line><line x1="481" x2="481" y1="31" y2="28"></line><line x1="521" x2="521" y2="3"></line><line x1="521" x2="521" y1="31" y2="28"></line><line x1="561" x2="561" y2="3"></line><line x1="561" x2="561" y1="31" y2="28"></line><line x1="601" x2="601" y2="3"></line><line x1="601" x2="601" y1="31" y2="28"></line></g><g><g></g><g transform="translate(20,-11)"></g><g transform="translate(20,15)"><g transform="translate(40)"><text y="6"><tspan>.first</tspan></text></g><g transform="translate(240)"><text y="6"><tspan>.second</tspan></text></g><g transform="translate(501)"><text y="6"><tspan>.third</tspan></text></g></g><g transform="translate(20,39)"></g></g></g><g transform="translate(4,-3)"><g transform="translate(20,11)"><text y="6">0</text></g><g transform="translate(100,11)"><text y="6">2</text></g><g transform="translate(140,11)"><text y="6">3</text></g><g transform="translate(381,11)"><text y="6">9</text></g><g transform="translate(421,11)"><text y="6">10</text></g><g transform="translate(621,11)"><text y="6">15</text></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
22
docs/stdlib/_images/data/union_layout.svg
Normal file
22
docs/stdlib/_images/data/union_layout.svg
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<!--
|
||||
Render the following with wavedrom-bitfield:
|
||||
|
||||
{
|
||||
"reg": [
|
||||
{"name": ".third", "bits": 6},
|
||||
{"name": "", "bits": 1, "type": 1},
|
||||
{"name": ".second", "bits": 7},
|
||||
{"name": ".first", "bits": 3},
|
||||
{"name": "", "bits": 4, "type": 1},
|
||||
],
|
||||
"config": {
|
||||
"lanes": 3,
|
||||
"compact": true,
|
||||
"vflip": true,
|
||||
"hspace": 289.4375
|
||||
}
|
||||
}
|
||||
|
||||
Then add 14 to height and viewBox.height.
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="289" height="132" viewBox="0 0 289 132" class="WaveDrom"><g transform="translate(0.5,0.5)" text-anchor="middle" font-size="14" font-family="sans-serif" font-weight="normal"><g transform="translate(4,83)"><g stroke="black" stroke-width="1" stroke-linecap="round"><line x2="280"></line><line x1="280" x2="280" y2="31"></line><line x2="280" y1="31" y2="31"></line><line y2="31"></line><line x1="40" x2="40" y2="3"></line><line x1="40" x2="40" y1="31" y2="28"></line><line x1="80" x2="80" y2="3"></line><line x1="80" x2="80" y1="31" y2="28"></line><line x1="120" x2="120" y2="3"></line><line x1="120" x2="120" y1="31" y2="28"></line><line x1="160" x2="160" y2="3"></line><line x1="160" x2="160" y1="31" y2="28"></line><line x1="200" x2="200" y2="3"></line><line x1="200" x2="200" y1="31" y2="28"></line><line x1="240" x2="240" y2="31"></line></g><g><g><rect x="240" width="40" height="31" field="" style="fill-opacity:0.1"></rect></g><g transform="translate(20,-11)"></g><g transform="translate(20,15)"><g transform="translate(100)"><text y="6"><tspan>.third</tspan></text></g><g transform="translate(240)"><text y="6"><tspan></tspan></text></g></g><g transform="translate(20,39)"></g></g></g><g transform="translate(4,52)"><g stroke="black" stroke-width="1" stroke-linecap="round"><line x2="280"></line><line x1="280" x2="280" y2="31"></line><line x2="280" y1="31" y2="31"></line><line y2="31"></line><line x1="40" x2="40" y2="3"></line><line x1="40" x2="40" y1="31" y2="28"></line><line x1="80" x2="80" y2="3"></line><line x1="80" x2="80" y1="31" y2="28"></line><line x1="120" x2="120" y2="3"></line><line x1="120" x2="120" y1="31" y2="28"></line><line x1="160" x2="160" y2="3"></line><line x1="160" x2="160" y1="31" y2="28"></line><line x1="200" x2="200" y2="3"></line><line x1="200" x2="200" y1="31" y2="28"></line><line x1="240" x2="240" y2="3"></line><line x1="240" x2="240" y1="31" y2="28"></line></g><g><g></g><g transform="translate(20,-11)"></g><g transform="translate(20,15)"><g transform="translate(120)"><text y="6"><tspan>.second</tspan></text></g></g><g transform="translate(20,39)"></g></g></g><g transform="translate(4,21)"><g stroke="black" stroke-width="1" stroke-linecap="round"><line x2="280"></line><line x1="280" x2="280" y2="31"></line><line x2="280" y1="31" y2="31"></line><line y2="31"></line><line x1="40" x2="40" y2="3"></line><line x1="40" x2="40" y1="31" y2="28"></line><line x1="80" x2="80" y2="3"></line><line x1="80" x2="80" y1="31" y2="28"></line><line x1="120" x2="120" y2="31"></line><line x1="160" x2="160" y2="3"></line><line x1="160" x2="160" y1="31" y2="28"></line><line x1="200" x2="200" y2="3"></line><line x1="200" x2="200" y1="31" y2="28"></line><line x1="240" x2="240" y2="3"></line><line x1="240" x2="240" y1="31" y2="28"></line></g><g><g><rect x="120" width="160" height="31" field="" style="fill-opacity:0.1"></rect></g><g transform="translate(20,-11)"></g><g transform="translate(20,15)"><g transform="translate(40)"><text y="6"><tspan>.first</tspan></text></g><g transform="translate(180)"><text y="6"><tspan></tspan></text></g></g><g transform="translate(20,39)"></g></g></g><g transform="translate(4,-3)"><g transform="translate(20,11)"><text y="6">0</text></g><g transform="translate(100,11)"><text y="6">2</text></g><g transform="translate(140,11)"><text y="6">3</text></g><g transform="translate(220,11)"><text y="6">5</text></g><g transform="translate(260,11)"><text y="6">6</text></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
228
docs/stdlib/data.rst
Normal file
228
docs/stdlib/data.rst
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
Data structures
|
||||
###############
|
||||
|
||||
.. py:module:: amaranth.lib.data
|
||||
|
||||
The :mod:`amaranth.lib.data` module provides a way to describe the bitwise layout of values and a proxy class for accessing fields of values using the attribute access and indexing syntax.
|
||||
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
|
||||
Overview
|
||||
++++++++
|
||||
|
||||
This module provides four related facilities:
|
||||
|
||||
1. Low-level bitwise layout description via :class:`Field` and :class:`Layout`. These classes are rarely used directly, but are the foundation on which all other functionality is built. They are also useful for introspection.
|
||||
2. High-level bitwise layout description via :class:`StructLayout`, :class:`UnionLayout`, :class:`ArrayLayout`, and :class:`FlexibleLayout`. These classes are the ones most often used directly, in particular :class:`StructLayout` and :class:`ArrayLayout`.
|
||||
3. Data views via :class:`View` or its user-defined subclasses. This class is used to apply a layout description to a plain :class:`Value`, enabling structured access to its bits.
|
||||
4. Data classes :class:`Struct` and :class:`Union`. These classes are data views with a layout that is defined using Python :term:`variable annotations <python:variable annotation>` (also known as type annotations).
|
||||
|
||||
|
||||
Motivation
|
||||
++++++++++
|
||||
|
||||
The fundamental Amaranth type is a :class:`Value`: a sequence of bits that can also be used as a number. Manipulating values directly is sufficient for simple applications, but in more complex ones, values are often more than just a sequence of bits; they have well-defined internal structure.
|
||||
|
||||
.. testsetup::
|
||||
|
||||
from amaranth import *
|
||||
m = Module()
|
||||
|
||||
For example, consider a module that processes pixels, converting them from RGB to grayscale. The color pixel format is RGB565:
|
||||
|
||||
.. image:: _images/data/rgb565_layout.svg
|
||||
|
||||
This module could be implemented (using a fast but *very* approximate method) as follows:
|
||||
|
||||
.. testcode::
|
||||
|
||||
i_color = Signal(16)
|
||||
o_gray = Signal(8)
|
||||
|
||||
m.d.comb += o_gray.eq((i_color[0:5] + i_color[5:11] + i_color[11:16]) << 1)
|
||||
|
||||
While this implementation works, it is repetitive, error-prone, hard to read, and laborous to change; all because the color components are referenced using bit offsets. To improve it, the structure can be described with a :class:`Layout` so that the components can be referenced by name:
|
||||
|
||||
.. testcode::
|
||||
|
||||
from amaranth.lib import data, enum
|
||||
|
||||
rgb565_layout = data.StructLayout({
|
||||
"red": 5,
|
||||
"green": 6,
|
||||
"blue": 5
|
||||
})
|
||||
|
||||
i_color = data.View(rgb565_layout)
|
||||
o_gray = Signal(8)
|
||||
|
||||
m.d.comb += o_gray.eq((i_color.red + i_color.green + i_color.blue) << 1)
|
||||
|
||||
The :class:`View` is :ref:`value-castable <lang-valuecasting>` and can be used anywhere a plain value can be used. For example, it can be assigned to in the usual way:
|
||||
|
||||
.. testcode::
|
||||
|
||||
m.d.comb += i_color.eq(0) # everything is black
|
||||
|
||||
|
||||
Composing layouts
|
||||
+++++++++++++++++
|
||||
|
||||
Layouts are composable: a :class:`Layout` is a :ref:`shape <lang-shapes>` and can be used as a part of another layout. In this case, an attribute access through a view returns a view as well.
|
||||
|
||||
For example, consider a module that processes RGB pixels in groups of up to four at a time, provided by another module, and accumulates their average intensity:
|
||||
|
||||
.. testcode::
|
||||
|
||||
input_layout = data.StructLayout({
|
||||
"pixels": data.ArrayLayout(rgb565_layout, 4),
|
||||
"valid": 4
|
||||
})
|
||||
|
||||
i_stream = data.View(input_layout)
|
||||
r_accum = Signal(32)
|
||||
|
||||
m.d.sync += r_accum.eq(
|
||||
r_accum + sum((i_stream.pixels[n].red +
|
||||
i_stream.pixels[n].green +
|
||||
i_stream.pixels[n].blue)
|
||||
* i_stream.valid[n]
|
||||
for n in range(len(i_stream.valid))))
|
||||
|
||||
Note how the width of ``i_stream`` is never defined explicitly; it is instead inferred from the shapes of its fields.
|
||||
|
||||
In the previous section, the precise bitwise layout was important, since RGB565 is an interchange format. In this section however the exact bit positions do not matter, since the layout is only used internally to communicate between two modules in the same design. It is sufficient that both of them use the same layout.
|
||||
|
||||
|
||||
Defining layouts
|
||||
++++++++++++++++
|
||||
|
||||
Data layouts can be defined in a few different ways depending on the use case.
|
||||
|
||||
In case the data format is defined using a family of layouts instead of a single specific one, a function can be used:
|
||||
|
||||
.. testcode::
|
||||
|
||||
def rgb_layout(r_bits, g_bits, b_bits):
|
||||
return data.StructLayout({
|
||||
"red": unsigned(r_bits),
|
||||
"green": unsigned(g_bits),
|
||||
"blue": unsigned(b_bits)
|
||||
})
|
||||
|
||||
rgb565_layout = rgb_layout(5, 6, 5)
|
||||
rgb24_layout = rgb_layout(8, 8, 8)
|
||||
|
||||
In case the data has related operations or transformations, :class:`View` can be subclassed to define methods implementing them:
|
||||
|
||||
.. testcode::
|
||||
|
||||
class RGBLayout(data.View):
|
||||
def __init__(self, target=None, *, r_bits, g_bits, b_bits, **kwargs):
|
||||
super().__init__(layout=data.StructLayout({
|
||||
"red": unsigned(r_bits),
|
||||
"green": unsigned(g_bits),
|
||||
"blue": unsigned(b_bits)
|
||||
}, target=target, **kwargs))
|
||||
|
||||
def brightness(self):
|
||||
return (self.red + self.green + self.blue)[-8:]
|
||||
|
||||
Here, the ``RGBLayout`` class itself is :ref:`shape-castable <lang-shapecasting>` and can be used anywhere a shape is accepted.
|
||||
|
||||
In case the data format is static, :class:`Struct` (or :class:`Union`) can be subclassed instead of :class:`View`, to reduce the amount of boilerplate needed:
|
||||
|
||||
.. testcode::
|
||||
|
||||
class IEEE754Single(data.Struct):
|
||||
fraction: 23
|
||||
exponent: 8 = 0x7f
|
||||
sign: 1
|
||||
|
||||
def is_subnormal(self):
|
||||
return self.exponent == 0
|
||||
|
||||
|
||||
Discriminated unions
|
||||
++++++++++++++++++++
|
||||
|
||||
This module provides a :class:`UnionLayout`, which is rarely needed by itself, but is very useful in combination with a *discriminant*: a enumeration indicating which field of the union contains valid data.
|
||||
|
||||
For example, consider a module that can direct another module to perform one of a few operations, each of which requires its own parameters. The two modules could communicate through a channel with a layout like this:
|
||||
|
||||
.. testcode::
|
||||
|
||||
class Command(data.Struct):
|
||||
class Kind(enum.Enum):
|
||||
SET_ADDR = 0
|
||||
SEND_DATA = 1
|
||||
|
||||
valid : 1
|
||||
kind : Kind
|
||||
params : data.UnionLayout({
|
||||
"set_addr": data.StructLayout({
|
||||
"addr": unsigned(32)
|
||||
}),
|
||||
"send_data": data.StructLayout({
|
||||
"byte": unsigned(8)
|
||||
})
|
||||
})
|
||||
|
||||
Here, the shape of the ``Command`` is inferred, being large enough to accommodate the biggest of all defined parameter structures, and it is not necessary to manage it manually.
|
||||
|
||||
One module could submit a command with:
|
||||
|
||||
.. testcode::
|
||||
|
||||
cmd = Command()
|
||||
|
||||
m.d.comb += [
|
||||
cmd.valid.eq(1),
|
||||
cmd.kind.eq(Command.Kind.SET_ADDR),
|
||||
cmd.params.set_addr.addr.eq(0x00001234)
|
||||
]
|
||||
|
||||
The other would react to commands as follows:
|
||||
|
||||
.. testcode::
|
||||
|
||||
addr = Signal(32)
|
||||
|
||||
with m.If(cmd.valid):
|
||||
with m.Switch(cmd.kind):
|
||||
with m.Case(Command.Kind.SET_ADDR):
|
||||
m.d.sync += addr.eq(cmd.params.set_addr.addr)
|
||||
with m.Case(Command.Kind.SEND_DATA):
|
||||
...
|
||||
|
||||
|
||||
Modeling structured data
|
||||
========================
|
||||
|
||||
.. autoclass:: Field
|
||||
.. autoclass:: Layout
|
||||
|
||||
|
||||
Common data layouts
|
||||
===================
|
||||
|
||||
.. autoclass:: StructLayout
|
||||
.. autoclass:: UnionLayout
|
||||
.. autoclass:: ArrayLayout
|
||||
.. autoclass:: FlexibleLayout
|
||||
|
||||
|
||||
Data views
|
||||
==========
|
||||
|
||||
.. autoclass:: View
|
||||
|
||||
|
||||
Data classes
|
||||
============
|
||||
|
||||
.. autoclass:: Struct
|
||||
.. autoclass:: Union
|
||||
Loading…
Add table
Add a link
Reference in a new issue