Electronic design in Swithft

Serendipitously, the first woman to be professionally employed as an electrical engineer in the United States was also named Edith.


Edith is a Swift library which can generate MLIR for CIRCT dialects. It also enables using CIRCT tools to output Verilog directly from the in-memory MLIR representation.

Getting Started

The root type in Edith is Circuit. Currently, the only thing circuits can do is define modules, which are analogous to Verilog modules. This is accomplished by conforming a type to the CircuitModule protocol, and the calling circuit.define on an instance of that type. Examples of this pattern can be found in Circuit Tests.

Installing CIRCT

The Tools/build-dependencies script installs CIRCT using MLIRSwift’s build-dependencies tool. The MLIRSwift documentation describes ways to customize this process. The Troubleshooting section has some useful information if you run into issues (particularly with pkg-config).

Snapshot Testing

We currently test Edith using snapshot tests, meaning instead of writing explicit unit tests we simply track the MLIR and Verilog output for a few designs. This is implemented using the snapshot function defined in Snapshot Test.swift. Snapshots can be updated by setting the EDITH_SNAPSHOT_OUTPUT_PATH environment variable like so: EDITH_SNAPSHOT_OUTPUT_PATH=$PWD/Tests/EdithTests/Snapshots swift test.

Design Principles

Only bind opinionated CIRCT dialects

The distinction here is between dialects that the circt community has discussed and blessed (like comb and the incoming seq), as compared to dialects which seek to represent existing languages with high fidelity (like firrtl and sv). The thought here is that the latter dialects are meant for compatibility with existing tools and thus have vestigial constructs which may not survive the CIRCT design process. This isn’t to say that dialects like the SystemVerilog dialect cannot or should not be bound, just that they should not be bound as part of Edith.

Push as much as possible into MLIR

MLIR is designed to support common program representations like abstract syntax trees. As such, we should avoid defining anything resembling an AST in Edith. Instead, Edith operations should directly create MLIR primitives. One common pattern is for operations of values to directly emit new MLIR operations into their operands’ block.