CoHDL 0.7.0 is out — cohdl self-update if you have it, or:
curl -fsSL https://raw.githubusercontent.com/conol-ai/cohdl/main/install.sh | sh
Subdesigns: typed composition for circuits
Every board has regions that are really one thing — a regulator and
its passives, a transceiver and its termination, an H-bridge and its
sense network. Until now CoHDL could reuse those only as
fn expansions: real components, but no boundary. The new
subdesign declaration (RFC-032) makes the boundary part of
the type system. Ports are the only electrical surface —
internals cannot be reached from outside — and each port carries the
same connection obligations a device pin does, so an unconnected
required port is a compile error at the use site, not a surprise at
bring-up.
subdesign MotorStage {
ports {
required IN1: Pin
required IN2: Pin
required VM: Pin
required GND: Pin
}
inst drv: motor_driver::MOTOR_DRV8231A
#[bypass(drv.VM, 100nF)]
inst c_vm_hf: passive::C_100n_10V_X5R_0402
inst c_vm_bulk_b: passive::C_10u_25V_X5R_0805
net _: IN1, drv.IN1
net _: IN2, drv.IN2
net _: VM, drv.VM, c_vm_hf.A, c_vm_bulk_b.A
net _: GND, drv.GND, c_vm_hf.B, c_vm_bulk_b.B
layout {
place drv at (0mm, 0mm)
place c_vm_hf at (-4mm, -1mm) rotate 90
}
}
design JointMC {
subdesign motor: MotorStage
net VBAT [7.4V]: conn_pwr.P1, motor.VM
layout {
place motor at (12mm, -6mm) rotate 90
// This board only: pull the bulk capacitor into the
// motor connector's current loop.
place motor.c_vm_bulk_b at (16.5mm, -2mm) rotate 90
}
}
The container itself never becomes a component: no designator, no BOM
row, no netlist entry. Ports dissolve into the nets they join, and what
reaches manufacturing is exactly the flat design you would have written
by hand — same designators, same bytes. Hierarchy survives where it
helps: instances keep Design::use::inst paths, generics and
arrays work on subdesigns exactly as they do on devices
(subdesign vr: Vreg<100nF>,
[CanPort; 2]), and subdesigns nest.
Layout composes the same way. A subdesign's internal
layout {} is a default: place the use site and
the whole cluster lands translated, rotated, and mirrored as one unit
— the back-side math is the same pad arithmetic the KiCad emitter is
verified against. When one board needs one component somewhere else,
place motor.c_vm_bulk_b at … reaches through the boundary
for placement only — explicit beats the default, and the electrical
surface stays sealed.
A joint motor controller, built from blocks
The new third example is a daisy-chainable CAN 2.0B joint node for a 2S pack: an STM32F072 with three subdesign regions around it — a JW5033S buck running the datasheet application verbatim, an SN65HVD230 CAN port in slope-control mode, and a DRV8231A H-bridge that regulates its own stall current with no firmware in the loop. Both existing examples were refactored onto subdesigns too, byte-identical outputs before and after. New library packages back it: can, motor-driver, and Micro-Fit 3.0 connectors, each with vendored datasheets and audited lands.
Hardened by review
The subdesign implementation went through an independent adversarial audit — thirty CLI and LSP probes against the shipped compiler — and a follow-up recheck. Every finding is closed and pinned by regression tests: a crash on physics attributes reaching a port, two silent component-loss paths, validation that used to wait for instantiation (a library now fails its own check rather than shipping a broken generic to its consumer), go-to-definition across subdesign boundaries, and a placement-precedence edge where an inert outer override could shadow a real default. The audit's own runners now pass 44/44.
CoHDL in Zed
Alongside the VS Code extension, the
repository now carries a
Zed extension: a tree-sitter grammar (validated against every source file in the
repository) plus the same cohdl lsp server — diagnostics
as you type, hover, go-to-definition, find-references. It finds
cohdl on your PATH or downloads the matching release on
its own. Until it lands in the Zed registry, install it as a dev
extension: Extensions → Install Dev Extension →
editors/zed in a checkout.
Full source and design record: github.com/conol-ai/cohdl.