Skip to main content

Packed data structure specifications for multi-language hardware projects

Project description

Packtype

Tests

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).

Installation

The easiest way to install Packtype is to use PyPI:

$> python3 -m pip install packtype

Alternatively, you can install the latest version directly from this repository:

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

Using Packtype

Packtype provides the packtype command line utility which can be used in conjuction with a specification (detailed below) to generate different types of outputs.

Rendering Code

A Packtype specification can be rendered into another programming language, for example SystemVerilog:

# Render SystemVerilog version of the specification
#  python -m packtype <SPEC>          code <LANG> <OUTDIR>
$> python -m packtype examples/structs/spec.py code sv ./output_dir

The positional arguments are:

  • SPEC - path to the Packtype specification file to process;
  • code - command to Packtype to render specification to code;
  • LANG - language to render (sv selects SystemVerilog);
  • OUTDIR - path to the output directory to write rendered files.

Then options are available to modify the behaviour:

  • --debug - generate debug messages as the tool runs.
  • --help - show the help prompt.

Rendering SVG

A Packtype struct can also be rendered to an SVG using the svg command:

# Render an SVG version of a struct
#  python3 -m packtype <SPEC>                 svg <STRUCT>      <OUTPUT>
$> python3 -m packtype examples/union/spec.py svg Encodings.Sub test.svg

The positional arguments are:

  • SPEC - path to the Packtype specification file to render;
  • svg - command to Packtype to render specification to an SVG;
  • STRUCT - hierarchy of the structure to render (e.g. <PACKAGE>.<STRUCT>);
  • OUTPUT - file to write the SVG to, if omitted it will print the output to STDOUT.

Example SVG

Examples

A number of examples are provided in the examples folder - each of these can be run by executing the test.sh file within the directory.

Packtype Specifications

Packtype specifications use a decorators and classes to declare the different data structures. Once a specification has been written, the Packtype utility can be used to generate code for different languages.

Package Declaration

Packages are signified using the @packtype.package() decorator, this declares a root object onto which constants, typedefs, enums, structs, and unions can be bound.

import packtype

@packtype.package()
class SomeProtocolPkg:
    """Contains definitions for some protocol"""
    ...

Constants

Numeric constants can be attached to the root of a package to share fixed values between different parts of implementation, verification, and firmware.

import packtype
from packtype import Constant

@packtype.package()
class SomeProtocolPkg:
    """Contains definitions for some protocol"""
    ADDRESS_WIDTH : Constant = 16
    DATA_WIDTH    : Constant = 32
    SIZE_WIDTH    : Constant = 8

Typedefs

Simple bitvector types can be declared within a package using the Scalar type, the parameterisation determines the bit-width of the structure:

import packtype
from packtype import Constant, Scalar

@packtype.package()
class SomeProtocolPkg:
    """Contains definitions for some protocol"""
    # Constants
    ADDRESS_WIDTH : Constant = 16
    # Simple Types
    Address : Scalar[ADDRESS_WIDTH]

Enumerations

Enumerations are declared using the @<PKG>.enum() decorator and can accept the following two attributes:

  • width - sets a fixed bit-width of the enumeration, this must be a positive integer;

  • mode - sets how entries of the enumeration are assigned values, the supported modes are:

    • EnumMode.INDEXED - Each value increments by one, starting at zero.
    • EnumMode.ONE_HOT - Each value sets exactly one bit position high (e.g. 1, 2, 4, 8).
    • EnumMode.GRAY - Values form a Gray code where only one bit flips between any two consecutive values.

Enumerations can either be declared with explicit or automatically incrementing values, or a mix of the two.

import packtype
from packtype import EnumMode

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

@DecoderPkg.enum(width=12)
class MessageType:
    """ Different message types with explicit values """
    PINGPONG : Constant = 0x123
    SHUTDOWN : Constant = 0x439
    POWERUP  : Constant = 0x752

@DecoderPkg.enum(mode=Enum.GRAY)
class DecoderState:
    """ Gray-coded states of the decoder FSM """
    DISABLED : Constant
    IDLE     : Constant
    HEADER   : Constant
    PAYLOAD  : Constant

Structs

Structs are declared using the @<PKG>.struct() decorator and can contain any number of fields that are simple scalar values, enumerations, or nested structs or unions. The decorator supports the following attributes:

  • width - sets a fixed bit-width of the struct, this must be a positive integer;
  • packing - determines the order in which declared fields are placed in the packed version:
    • Packing.FROM_LSB - place fields starting at the least-significant bit;
    • Packing.FROM_MSB - place fields starting from the most-significant bit.
import packtype
from packtype import Scalar

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

@DecoderPkg.struct(width=32)
class MessageHeader:
    """ Common header for all messages """
    target_id : Scalar[8]
    msg_type  : MessageType

@DecoderPkg.struct() # Width calculated from field sizes
class PingPongPayload:
    """ Payload of a ping-pong keepalive message """
    source_id  : Scalar[ 8]
    is_pong    : Scalar[ 1]
    ping_value : Scalar[15]
    timestamp  : Scalar[ 8]

@DecoderPkg.struct()
class PingPongMessage:
    """ Full message including header and payload """
    header  : MessageHeader
    payload : PingPongPayload

By default, fields are packed into data structures from the LSB - but this can be reversed to pack from the MSB by providing the packing=Packing.FROM_MSB argument to the decorator. For example:

import packtype
from packtype import Packing, Scalar

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

@DecoderPkg.struct(packing=Packing.FROM_MSB, width=32)
class PingPongPayload:
    """ Payload of a ping-pong keepalive message """
    source_id  : Scalar[ 8]
    is_pong    : Scalar[ 1]
    ping_value : Scalar[15]
    timestamp  : Scalar[ 8]

You can also render using Jupyter notebooks, see example.ipynb as an example

Unions

Unions allow different data structures to form different projections over the same raw bits - this is especially useful in protocol decoders where a bus may carry different formats and structures of data in different cycles. All components of a union must be of the same size, otherwise the tool will raise an error.

import packtype
from packtype import Scalar

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

@DecoderPkg.union()
class MessageBus:
    """ Union of the different message phases of the bus """
    raw       : Scalar[32]
    header    : MessageHeader
    ping_pong : PingPongPayload

Profiling

Using Packtype objects within a testbench can cause significant overhead if many pack and unpack operations are being performed. To help diagnose performance issues, you can enable profiling which counts the number of each type of object that are created during a run:

from packtype.base import Base

def my_test_function():
    Base._pt_enable_profiling(limit=10)

The limit keyword will filter out any objects from the report that have less than this number of creations by the end of the run, this can be useful to filter out noise of many small unique objects.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

packtype-2.1.0.tar.gz (43.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

packtype-2.1.0-py3-none-any.whl (58.1 kB view details)

Uploaded Python 3

File details

Details for the file packtype-2.1.0.tar.gz.

File metadata

  • Download URL: packtype-2.1.0.tar.gz
  • Upload date:
  • Size: 43.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.13.3 Darwin/24.5.0

File hashes

Hashes for packtype-2.1.0.tar.gz
Algorithm Hash digest
SHA256 6ded4b4bb113aa49710fab4c7daa07bf72a9b9d84b6af90e19e2dd3a79eedf9e
MD5 f06d90bbebc78d634bccfa095111d006
BLAKE2b-256 9be7f052a2d96f05ec80c96b3cac6dd2b0cf9ffa4a926c3e7069c5b705c7b372

See more details on using hashes here.

File details

Details for the file packtype-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: packtype-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 58.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.13.3 Darwin/24.5.0

File hashes

Hashes for packtype-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 825521b32cadaed471e53c4cbc1449a92b610560c11e9aa02c57b928147d3837
MD5 a1acbbb7065139130b5d23015497b04a
BLAKE2b-256 7be39bae0881146367ff38f4c430d7a98e7310a72588005625cf2eeba3fdc1ec

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page