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
55 changes: 55 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Packtype Documentation

on:
pull_request:
push:
branches:
- main

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages : write
id-token: write

# Allow only one concurrent deployment to GitHub pages, but don't cancel running
# builds and wait for completion
concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build_docs:
name : Build Documentation
runs-on : ubuntu-latest
timeout-minutes: 15
steps :
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: 3.11
- name : Install Poetry and environment
shell: bash
run : |
python -m pip install --upgrade pip
python -m pip install poetry
poetry install --with dev --with docs
- name: Build documentation
run: |
poetry run mkdocs build
- name: Upload documentation artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./site

deploy_docs:
name : Deploy Documentation
runs-on : ubuntu-latest
timeout-minutes: 15
needs :
- build_docs
steps :
- name: Deploy to GitHub pages
id: deployment
uses: actions/deploy-pages@v4
2 changes: 1 addition & 1 deletion .github/workflows/pr_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12"]
python-version: ["3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v2
Expand Down
11 changes: 1 addition & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@

Packtype is a Python framework for describing packed data structures for use in low-level hardware design, verification, and firmware development. From this single specification, equivalent implementations for different languages can be generated (for example SystemVerilog).

The support matrix below shows the current support:

| Language | Constants | Enums | Structs | Unions | Packages |
|---------------|:---------:|:-----:|:-------:|:------:|:--------:|
| Python | Yes | Yes | Yes | Yes | Yes |
| SystemVerilog | Yes | Yes | Yes | Yes | Yes |

**NOTE** Support for C and C++ is currently missing from version 2, but was present in version 1 - this regression will be addressed in a future revision.

## Installation

The easiest way to install Packtype is to use PyPI:
Expand All @@ -24,7 +15,7 @@ $> python3 -m pip install packtype
Alternatively, you can install the latest version directly from this repository:

```
$> python3 -m pip install git+git://github.com/Intuity/packtype
$> python3 -m pip install git+https://github.com/Intuity/packtype
```

## Using Packtype
Expand Down
20 changes: 20 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Packtype is used to define constants and packed data structures using a syntax
similar to Python [dataclasses](https://docs.python.org/3/library/dataclasses.html),
these definitions can then be interrogated, rendered into various output formats,
or used natively in Python. The project originated from a need to sample and
drive structs and union ports on the boundary of SystemVerilog designs from
cocotb in non-commercial simulators.

## Installation

The easiest way to install Packtype is to use PyPI:

```
$> python3 -m pip install packtype
```

Alternatively, you can install the development branch directly from the repository:

```
$> python3 -m pip install git+https://github.com/Intuity/packtype
```
41 changes: 41 additions & 0 deletions docs/syntax/alias.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Type aliases allow one type to be referenced and renamed as another, which can
be used to create a localised reference to a foreign type.

## Example

The packtype definition:

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

@packtype.package()
class PackageA:
TypeA : Scalar[5]

@packtype.package()
class PackageB:
TypeB : Alias[PackageA.TypeA]
```

As rendered to SystemVerilog:

```sv linenums="1"
package package_a;
typedef logic [4:0] type_a_t;
endpackage : package_a

package package_b;
import package_a::type_a_t;
typedef type_a_t type_b_t;
endpackage : package_b
```

## Syntax

```python
@packtype.package()
class PackageB:
# Format <NAME> : Alias[<TYPE_TO_ALIAS>]
TypeB : Alias[PackageA.TypeA]
```
87 changes: 87 additions & 0 deletions docs/syntax/constant.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
Constants are defined using the `Constant` type and are declared directly within
the [package](package.md). They carry a fixed value, which may be computed from
other constants, and may be given an explicit bit width.

## Example

The packtype definition:

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

@packtype.package()
class MyPackage:
VALUE_A : Constant = 123
VALUE_B : Constant[16] = 234
```

As rendered to SystemVerilog:

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

localparam VALUE_A = 123;
localparam bit [7:0] VALUE_B = 234;

endpackage : my_package
```

## Syntax

### Unsized Constants

A constant defined without an explicit size will be treated as unsized and it
will be left to the target language template to decide what size container to
allocate it.

```python
@packtype.package()
class MyPackage:
# Format: <NAME> : Constant = <VALUE>
MY_CONSTANT : Constant = 123
```

### Implicit Constants

Unsized constants may be declared implicitly by omitting the `: Constant` keyword
from the declaration:

```python
@packtype.package()
class MyPackage:
# Format: <NAME> = <VALUE>
MY_CONSTANT = 123
```

### Sized Constants

Constants may be defined with an explicit bit width, in which case Packtype will
respect the request bit width internally and target language templates will
allocate the nearest possible size large enough to hold the full range of that
number of bits.

```python
@packtype.package()
class MyPackage:
# Format: <NAME> : Constant[<WIDTH>] = <VALUE>
MY_CONSTANT : Constant[8] = 123
```

## Oversized Values

When using explicitly sized constants, if a value is allocated to the constant
that is outside the legal range a `ValueError` will be raised:

```python
@packtype.package()
class MyPackage:
# Attempt to store 123 in a 4 bit value
MY_CONSTANT : Constant[4] = 123
```

Will lead to:

```bash
ValueError: 123 is out of 4 bit range (0 to 15)
```
106 changes: 106 additions & 0 deletions docs/syntax/enum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
Enums are defined using the `@<PACKAGE>.enum()` decorator, which both processes
the entries contained within them and associates them to the [package](package.md).
Entries of an enum can be given explicit values or enumerated automatically with
various different value patterns. The width of an enum can be defined explicitly
or inferred from the largest value encoded within it.

## Example

The packtype definition:

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

@packtype.package()
class MyPackage:
...

@MyPackage.enum()
class Fruit:
"""Description of the enumeration can go here"""
APPLE : Constant
ORANGE : Constant
PEAR : Constant
BANANA : Constant
```

As rendered to SystemVerilog:

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

typedef enum logic [1:0] {
FRUIT_APPLE,
FRUIT_ORANGE,
FRUIT_PEAR,
FRUIT_BANANA
} fruit_t;

endpackage : my_package
```

## Decorator Options

The decorator accepts options that modify the enum declaration:

| Name | Default | Description |
|----------|-----------------------|--------------------------------------------|
| `mode` | `EnumMode.INDEXED` | Defines how inferred values are assigned |
| `width` | Inferred by max value | Specifies the bit-width of the enum type |
| `prefix` | `None` | Customise the prefix in rendered languages |

The `mode` parameter may be set to one of the following values:

* `EnumMode.INDEXED` - values start from `0` and are chosen sequentially;
* `EnumMode.ONE_HOT` - values start from `1` and are chosen to have exactly one
active bit (i.e powers of 2) so follow the sequence `1`, `2`, `4`, `8`, ...;
* `EnumMode.GRAY` - values start from `0` and are assigned following a Gray
code (only one bit changes between sequentially assigned values), an
`EnumError` will be raised where not enough named constants are declared to
fill the Gray code sequence.

The `width` parameter may be omitted, in which case it is automatically inferred
as the ceiling log2 of the maximum enumerated value. Where it is specified, an
`EnumError` will be raised if the maximum enumerated value exceeds what can be
expressed within the enum's bit width.

The `prefix` may be used when rendering to languages that do not support name
spacing of enumerated types - for example in SystemVerilog the names of the
enumerated values will be `<PREFIX>_<VALUE_NAME>`. If omitted, the prefix will
be inferred as the shouty snake case version of the enumeration's name.

## Explicit Values

Values within an enumeration can be assigned explicit values, these may be
interspersed with implicitly assigned values and the tool will adopt explicit
values and continue to enumerate from that point:

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

@Types.enum(width=8)
class Opcodes:
ALU_ADD : Constant = 0x10
ALU_SUB : Constant # Infers 0x11
ALU_MUL : Constant # Infers 0x12
LDST_LB : Constant = 0x20
LDST_LH : Constant # Infers 0x21
LDST_LW : Constant # Infers 0x22
LDST_SB : Constant = 0x30
LDST_SH : Constant # Infers 0x31
LDST_SW : Constant # Infers 0x32
```

## Helper Properties and Methods

Enum definitions expose a collection of helper functions for properties related
to the enumeration:

* `<ENUM>._pt_width` - property that returns the bit width of the enumerated
values;
* `<ENUM>._pt_mask` - property that returns a bit mask matched to the width of
the enumerated value (i.e. `(1 << MyEnum._pt_width) - 1`);
* `<ENUM>._pt_as_dict()` - function that returns a dictionary of the values
of the enumeration with the key as the name as the value as the integer value;
Loading