Skip to main content

A Python HDL inspired by Chisel

Project description

plane

coverage

Plane Logo

Install

Requires Python 3.12+.

uv add plane

Quick Start

from plane import *

class Blink(Module):
    def elaborate(self):
        self.clk = IO(Input(Clock()), name="clk")
        self.rst = IO(Input(AsyncLowReset()), name="rst")
        self.led = IO(Output(Bool()), name="led")
        self.counter = Reg(UInt(24), init=0, name="counter")
        self.counter @= self.counter + Literal(1, 24)
        self.led @= self.counter[23]
print(emitVerilog(Blink()))
module Blink (
  input  logic clk,
  input  logic rst,
  output logic led
);

  logic [23:0] counter;

  assign led = counter[23];

  always_ff @(posedge clk or negedge rst) begin
    if (!rst) begin
      counter <= 24'd0;
    end else begin
      counter <= (counter + 24'd1);
    end
  end

endmodule

See docs/ for the full guide.

Motivation

A PythonHDL inspired by Chisel

Chisel is a powerful HDL based on Scala. While powerful, it being based on Scala has some downsides with regards to interopting with various other flows in a semiconductor design cycle. For better or for worse, Python has become the dominant language for scripting various flows (and now AI pipelines) and therefore it seemed prudent to have a way to build SystemVerilog utilizing a Python based HDL. There are other Python HDLs out there Amaranth, Migen, MyHDL, etc. This library was not created to supersede those, but meerly to coexist and offer another solution.

The name "Plane" is meant as a play on word in a few ways:

  1. Plane to sound similar to "plain", indicating this is a slightly simple library
  2. Plane as in a plane woodworking tool, paying a homage to Chisel. Where a Chisel would require precise, fine tune actions, a plane just uses brute forcce to get something done.

Many of Chisel's concepts have been used here in Plane. Certain structures are modified as necessary for the differences in Python and Scala. Plane is not as feature rich as the Chisel ecosystem, and the long term plan is for it not to be.

Features

  • Data types: UInt, SInt, Bool, Clock, Reset, PlaneEnum, Vec
  • Modules, ports, Bundle structured interfaces
  • Combinational (AlwaysComb) and sequential (Reg, RegNext) logic
  • Control flow: When/ElseWhen/Otherwise, Switch/Case/Default
  • Parameters and blackboxes
  • Comments in emitted Verilog
  • CSR subsystem: RegisterBlock/RegisterSystem, field types, APB adapters
  • Collateral generation: YAML, UVM RAL, HTML

SystemVerilog Emission

Most issues with meta-language HDLs is the undoubtly the emitted RTL that is produced. FSMs in particular are quite difficult to look at for Chisel-generated RTL. Plane's design was really built with verilog emission being a core principle. Most of the lifecycle for some RTL is spent being read versus modified. For this reason, we want the RTL that is produced to be as close to human-readable as possible. There are times this is difficult depending on your usecases, however many of the features and/or language decisions were chosen to aid in emission quality. If anything, this was the main motivation for Plane. This means the Plane HDL looks similar to SV in nature. This was a design decision to make it clear what you were designing and to ease the transition for regular RTL designers.

FSM Showcase

A simple 3-state FSM that advances to the next state when advance is high, otherwise holds. This shows AlwaysComb, Switch/Case, and When working together:

from plane import *

class State(PlaneEnum):
    A = 0
    B = 1
    C = 2

class SimpleFSM(Module):
    def elaborate(self):
        self.clk = IO(Input(Clock()), name="clk")
        self.rst = IO(Input(AsyncLowReset()), name="rst")
        self.advance = IO(Input(Bool()), name="advance")
        self.state = IO(Output(State), name="state")

        self.state_reg = Reg(State, init=State.A, name="state_reg", optimize=False)
        self.state_next = Wire(State, name="state_next")

        with AlwaysComb():
            self.state_next @= self.state_reg  # default: hold
            with Switch(self.state_reg):
                with Case(State.A):
                    with When(self.advance):
                        self.state_next @= State.B
                with Case(State.B):
                    with When(self.advance):
                        self.state_next @= State.C
                with Case(State.C):
                    with When(self.advance):
                        self.state_next @= State.A

        self.state_reg @= self.state_next
        self.state @= self.state_reg

Emitted Verilog:

package SimpleFSM_pkg;
  typedef enum logic [1:0] { A, B, C } State_t;
endpackage

module SimpleFSM (
  input  logic       clk,
  input  logic       rst,
  input  logic       advance,
  output logic [1:0] state
);

  import SimpleFSM_pkg::*;

  State_t state_next;
  State_t state_reg;

  assign state = state_reg;

  always_comb begin
    state_next = state_reg;
    case (state_reg)
      State_t::A: begin
        if (advance) begin
          state_next = State_t::B;
        end
      end
      State_t::B: begin
        if (advance) begin
          state_next = State_t::C;
        end
      end
      State_t::C: begin
        if (advance) begin
          state_next = State_t::A;
        end
      end
    endcase
  end

  always_ff @(posedge clk or negedge rst) begin
    if (!rst) begin
      state_reg <= State_t::A;
    end else begin
      state_reg <= state_next;
    end
  end

endmodule

AI Usage

The base level library was coded using locally hosted models (Qwen3.5-27b-Q4_K_M and Qwen3.6-27b-Q4_K_M (with and without MTP)). These were run on a server with a i7-6950X, 64GB 2400MHz DDR4, and using an AMD R9700 PRO 32GB. This setup allowed roughly 200k of context and OpenCode was used as the coding harness.

As much as this was an exercise in creating an HDL library for simple usecases, it also was an exercise to see how powerful locally hosted models have become and where their limits were. While certainly not the level of Sonnet/Opus/Gemini/OpenAI, these models still punched above their weight (even if Qwen3.6 has this tendency to royally screw up the indentation on an edit).

Going forward, various models may be used depending on the feature, experiementation, or even just because I'm tired of my office getting hot due to the GPU computing.

While a model did write the majority of this library, I would hesitate to call it "vibe coded". The model was never given complete control to edit and changes were thoroughly reviewed. That being said, there will certainly be cases of areas that could be more robust.

Agent Skills

The skills/ directory contains SKILL.md files for coding harnesses. Copy skills/plane-hdl/ and skills/plane-csr/ into your ~/.claude/skills/ or ~/.config/opencode/skills/ directory for auto-discovery when working with plane.

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

plane_hdl-0.1.0.tar.gz (71.9 kB view details)

Uploaded Source

Built Distribution

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

plane_hdl-0.1.0-py3-none-any.whl (56.1 kB view details)

Uploaded Python 3

File details

Details for the file plane_hdl-0.1.0.tar.gz.

File metadata

  • Download URL: plane_hdl-0.1.0.tar.gz
  • Upload date:
  • Size: 71.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for plane_hdl-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f4542b095b42dd43fcc8cae10f98df71326de957f0f07c64a34e926b4a5bf1e4
MD5 cfe8be13bdbb624badbcc99558d3f156
BLAKE2b-256 ebbdae30f87f0882a06783e37a794dc475c1bc865e0062d22a7684f395e6fc0e

See more details on using hashes here.

Provenance

The following attestation bundles were made for plane_hdl-0.1.0.tar.gz:

Publisher: publish.yml on lsteveol/plane

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file plane_hdl-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: plane_hdl-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 56.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for plane_hdl-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f41dbd27f20da6bd0d63243f92683ad20f3d0558e3fa5c25227971bc28cc9cb1
MD5 5183fa19fb1683af5fe5d588f44525d3
BLAKE2b-256 993a4c2346a03a110c5600d1cbc46a162144e3d1dea2882dd9cde5c38a113075

See more details on using hashes here.

Provenance

The following attestation bundles were made for plane_hdl-0.1.0-py3-none-any.whl:

Publisher: publish.yml on lsteveol/plane

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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