Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions docs/syntax/arrays.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
Multi-dimensional arrays are often used to represented dimensionally structured
data. Packtype's syntax allows any type to be arrayed with an arbitrary number
of dimensions and dimension sizes. The base type can be a simple [scalar](scalar.md),
or can reference a more complex type like a [struct](struct.md) or [union](union.md),
you can even reference another multi-dimensional array!

## Example

The Packtype definition can either use a Python dataclass style or the Packtype
custom grammar:

=== "Python (.py)"

```python linenums="1"
import packtype
from packtype import Constant, Scalar

@packtype.package()
class Package1D:
Scalar1D : Scalar[4]

@Package1D.struct()
class Struct1D:
field_a : Scalar[2]
field_b : Scalar[3]

@packtype.package()
class Package3D:
Scalar3D : Package1D.Scalar1D[4][5]
Struct3D : Package1D.Struct1D[3][2]
```

=== "Packtype (.pt)"

```sv linenums="1"
package package_1d {
scalar_1d_t : scalar[4]

struct struct_1d_t {
field_a : scalar[2]
field_b : scalar[3]
}
}

package package_3d {
scalar_3d_t : package_1d::scalar_1d_t[4][5]
struct_3d_t : package_1d::struct_1d_t[3][2]
}
```

As rendered to SystemVerilog

```sv linenums="1"
package package_1d;

typedef logic [3:0] scalar_1d_t;

typedef struct packed {
logic [2:0] field_b;
logic [1:0] field_a;
} struct_1d_t;

endpackage : package_1d

package package_3d;

import package_1d::scalar_1d_t;
import package_1d::struct_1d_t;

typedef scalar_1d_t [4:0][3:0] scalar_3d_t;
typedef struct_1d_t [1:0][2:0] struct_3d_t;

endpackage : package_3d
```

!!! warning

The order of dimensions is _reversed_ when compared to declaring a packed
multi-dimensional array in SystemVerilog. For example `scalar[4][5][6]`
declares a 6x5 array of 4-bit elements, which in SystemVerilog would be
written `logic [5:0][4:0][3:0]`. This is done to make it easier to parse the
syntax, as decisions can be made reading left-to-right.

## Helper Properties and Methods

Struct definitions expose a collection of helper functions for properties related
to the type:

* `<ARRAY>._pt_width` - property that returns the bit width of the entire array;
* `<ARRAY>._pt_pack()` - packs all values contained within the array into a
singular integer value (can also be achieved by casting to an int, e.g.
`int(<ARRAY>)`);
* `<ARRAY>._pt_unpack(packed: int)` - unpacks an integer value into the entries
of the array;
* `len(<ARRAY>)` - returns the size of the outermost dimension of the array;
* `<ARRAY>[X]` - accesses element X within the array, which may return either
an instance of the base type _or_ another packed array depending on the
number of dimensions.
30 changes: 15 additions & 15 deletions docs/syntax/scalar.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ custom grammar:

=== "Python (.py)"

```python linenums="1"
import packtype
from packtype import Constant, Scalar

@packtype.package()
class MyPackage:
# Constants
TYPE_A_W : Constant = 29
TYPE_B_W : Constant = 13

# Typedefs
TypeA : Scalar[TYPE_A_W]
TypeB : Scalar[TYPE_B_W]
TypeC : Scalar[7]
```
```python linenums="1"
import packtype
from packtype import Constant, Scalar

@packtype.package()
class MyPackage:
# Constants
TYPE_A_W : Constant = 29
TYPE_B_W : Constant = 13

# Typedefs
TypeA : Scalar[TYPE_A_W]
TypeB : Scalar[TYPE_B_W]
TypeC : Scalar[7]
```

=== "Packtype (.pt)"

Expand Down
33 changes: 33 additions & 0 deletions examples/arrays/spec.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package one_dimension {
scalar_1d : scalar[4]

struct struct_1d {
field_a : scalar[4][3][2]
field_b : scalar[2][3][4]
}

enum enum_1d {
VAL_A: constant
VAL_B: constant
VAL_C: constant
}

union union_1d {
member_a: struct_1d[2][3]
member_b: scalar[4][12][2][3]
}
}

package two_dimension {
scalar_2d : one_dimension::scalar_1d[3]
enum_2d : one_dimension::enum_1d[2]
struct_2d : one_dimension::struct_1d[4]
union_2d : one_dimension::union_1d[2]
}

package three_dimension {
scalar_3d : two_dimension::scalar_2d[2]
enum_3d : two_dimension::enum_2d[4]
struct_3d : two_dimension::struct_2d[5]
union_3d : two_dimension::union_2d[3]
}
42 changes: 42 additions & 0 deletions examples/arrays/spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import packtype
from packtype import Constant, Scalar


@packtype.package()
class OneDimension:
Scalar1D: Scalar[4]


@OneDimension.struct()
class Struct1D:
field_a: Scalar[4][3][2]
field_b: Scalar[2][3][4]


@OneDimension.enum()
class Enum1D:
VAL_A: Constant
VAL_B: Constant
VAL_C: Constant


@OneDimension.union()
class Union1D:
member_a: Struct1D[2][3]
member_b: Scalar[4][12][2][3]


@packtype.package()
class TwoDimension:
Scalar2D: OneDimension.Scalar1D[3]
Enum2D: OneDimension.Enum1D[2]
Struct2D: OneDimension.Struct1D[4]
Union2D: OneDimension.Union1D[2]


@packtype.package()
class ThreeDimension:
Scalar3D: TwoDimension.Scalar2D[2]
Enum3D: TwoDimension.Enum2D[4]
Struct3D: TwoDimension.Struct2D[5]
Union3D: TwoDimension.Union2D[3]
17 changes: 17 additions & 0 deletions examples/arrays/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

# Copyright 2023-2025, Peter Birch, mailto:peter@intuity.io
# SPDX-License-Identifier: Apache-2.0
#

# Credit to Dave Dopson: https://stackoverflow.com/questions/59895/how-can-i-get-the-source-directory-of-a-bash-script-from-within-the-script-itsel
this_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

# Setup PYTHONPATH to get access to packtype
export PYTHONPATH=${this_dir}/../..:$PYTHONPATH

# Invoke packtype on Python syntax
python3 -m packtype --debug code package sv ${this_dir}/out_py ${this_dir}/spec.py

# Invoke packtype on Packtype syntax
python3 -m packtype --debug code package sv ${this_dir}/out_pt ${this_dir}/spec.pt
4 changes: 2 additions & 2 deletions examples/axi4l_registers/registers.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class ResetControl:

@packtype.registers.group()
class ControlGroup:
core_reset: 4 * ResetControl
core_reset: ResetControl[4]


# === Communications ===
Expand Down Expand Up @@ -76,4 +76,4 @@ class CommsGroup:
class Control:
device: DeviceGroup
control: ControlGroup
comms: 2 * CommsGroup
comms: CommsGroup[2]
4 changes: 2 additions & 2 deletions examples/raw_registers/registers.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class ResetControl:

@packtype.registers.group()
class ControlGroup:
core_reset: 4 * ResetControl
core_reset: ResetControl[4]


# === Communications ===
Expand Down Expand Up @@ -76,4 +76,4 @@ class CommsGroup:
class Control:
device: DeviceGroup
control: ControlGroup
comms: 2 * CommsGroup
comms: CommsGroup[2]
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ nav:
- Packtype: index.md
- Syntax:
- Alias: syntax/alias.md
- Arrays: syntax/arrays.md
- Constants: syntax/constant.md
- Enumerations: syntax/enum.md
- Packages: syntax/package.md
Expand Down
Loading