Weave IP-XACT components into SoC designs from a YAML file: generated SystemVerilog top, filelists, FPGA and ASIC flow scripts. A CLI/file-based alternative to Kactus2, friendly to humans and AI agents.
Project description
weft
Weave IP-XACT components into SoC designs — from a file, not a GUI.
weft reads IEEE 1685-2014 IP-XACT component descriptions, takes a small
YAML design file, and emits everything needed to build the SoC: a generated
SystemVerilog top, a compile-order filelist, an FPGA build script (Vivado)
and a silicon synthesis script (sv2v + yosys), plus a wiring report. It
replaces the pointy-clicky part of tools like Kactus2 with something people
and AI agents can drive, diff, and code-review.
pip install weft-soc
weft ls path/to/ipxact/ # what components do I have?
weft check my_soc.yaml # parse + weave, report issues
weft map my_soc.yaml --svg map.svg # validate + draw the address map
weft headers my_soc.yaml -o regs.h # C header from the register maps
weft gen my_soc.yaml -o out/ --tb # generate the SoC (+ cocotb TB)
weft tb my_soc.yaml -o out/ # just the cocotb testbench
weft lint my_soc.yaml # generate + Verilator-lint it
# out/: my_soc.sv, my_soc.f, build_fpga.tcl, build_asic.sh, report.md,
# address_map.md, address_map.svg, my_soc_regs.h,
# runner.py, test_regs.py (headers/map when address_map is set;
# TB with --tb)
What it generates
| Output | From | For |
|---|---|---|
<top>.sv |
the weave | synthesizable SoC top |
<top>.f |
component fileSets | compile-order filelist |
build_fpga.tcl |
design + weave | timing-gated Vivado OOC flow |
build_asic.sh |
design + weave | sv2v + yosys silicon synthesis (LIBERTY= to map cells) |
address_map.{md,svg} |
address_map |
validated map + proportional diagram |
<top>_regs.h |
IP-XACT memoryMaps | C #defines: bases, offsets, absolute addrs, field masks/shifts |
runner.py + test_regs.py |
memoryMaps + weave | cocotb runner + auto register-regression (reset check + R/W round-trip over every register) |
Run the generated testbench with pip install cocotb and a supported
simulator (e.g. Verilator) on PATH, then python runner.py in the output
directory. The register-regression drives the promoted AXI4-Lite manager
port; if the design promotes none, weft emits a clock/reset smoke stub
instead and says so.
The only new RTL is the generated top; by default the filelist references
each IP's original sources in place (relative paths), so the component
repos stay the single source of truth. Pass --bundle to instead copy every
referenced source into out/src/<component>/… (one subfolder per IP,
preserving each component's internal layout) — the output directory then
ships as one self-contained artifact. The ASIC flow additionally produces a single flattened
<top>.flat.v via sv2v as its intermediate.
The design file
top: soc_demo # generated module name
part: xc7a100tcsg324-1 # optional: FPGA part for build_fpga.tcl
clocks: [clk] # optional: constrained in flow scripts
libraries: # dirs scanned recursively for IP-XACT
- ../aes/ipxact
- ../xbar/ipxact
instances:
xbar0: {vlnv: "hasankursun.dev:ip:xbar_axil:1.0"}
uart0: {vlnv: "hasankursun.dev:ip:uart_axil:1.0"}
ila0: {vlnv: "hasankursun.dev:ip:ila_axil:1.0", params: {DEPTH: 256}}
connections: # bus interface <-> bus interface
- xbar0.m00_axi <-> uart0.s_axi
- xbar0.m01_axi <-> ila0.s_axi
external: # promote to top-level ports
ctrl: {interface: xbar0.s00_axi} # whole bus interface
tx: {port: uart0.tx_o} # single port
clk: {drive: [xbar0.aclk, uart0.aclk, ila0.aclk]} # fanned-out input
assigns: # raw escape hatch; wires are
- "ila0_probe_i = {30'd0, uart0_tx_o, uart0_rx_i}" # {instance}_{port}
address_map: # friendly base/size per peripheral
uart0: {base: 0x0000_0000, size: 0x1000}
ila0: {base: 0x0000_1000, size: 0x1000}
params_from_map: [xbar0] # derive this interconnect's BASE/MASK
Address map, interconnect derivation, and the "configure, don't generate" stance
weft map validates the address map — power-of-two sizes, natural
alignment, no overlap, and each window at least as large as the IP's own
register span — and fails loudly on any violation (the classic silent SoC
killer, caught statically). params_from_map then derives the crossbar's
BASE/MASK parameters from that map, so the address map is the single
source of truth and the interconnect can't disagree with the headers or the
docs.
Note the deliberate choice: weft configures a formally-proven interconnect
IP (xbar_axil, with a proven fairness bound and end-to-end proofs) rather
than emitting fresh, unverified crossbar RTL. The map decides addresses; the
proven RTL does the decoding.
Semantics
- Connections match the logical port names shared by the two
interfaces' port maps (
AWADDR,TDATA, …), honouringpartSelectslices — interconnects that expose per-index interfaces as slices of flat vectors work out of the box. Bus VLNVs must match; master/slave modes are checked. - Robustness ("never emit a broken top"): width mismatches connect the
low bits with a warning (e.g. a 32-bit crossbar address meeting an 8-bit
peripheral); one-sided logicals warn and zero-tie receivers; any instance
input bits left undriven are zero-tied with a warning. Every decision is
in
report.md. - Parameters are passed through verbatim (bit-vector literals fine) and
used to evaluate expression port widths like
ADDR_W-1. Note that IP-XACT components describe one static configuration — if a component was generated for a 2×4 crossbar, instantiate it as 2×4 or regenerate its XML. - FPGA vs silicon:
build_fpga.tclruns a timing-gated Vivado out-of-context flow (bring your own XDC for a board build);build_asic.shflattens with sv2v and synthesizes with yosys, mapping to your standard cells whenLIBERTY=is provided.
Tested against a real portfolio
The examples/soc_demo.yaml design weaves four independently-verified IPs (AES crypto core, AXI4-Lite crossbar, UART, internal logic analyzer — each with formal proofs and on-board validation) into a Verilator-clean SoC. The unit suite runs on self-contained fixtures; the integration test picks up the sibling repos when present.
Development
pip install -e .[dev]
pytest
Releases are automated: pushing a v* tag builds and publishes to PyPI via
GitHub Actions trusted publishing (see .github/workflows/release.yml).
License
Apache-2.0. Copyright 2026 Hasan Kurşun.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file weft_soc-0.1.0.tar.gz.
File metadata
- Download URL: weft_soc-0.1.0.tar.gz
- Upload date:
- Size: 31.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
532c136863548283c877a1b32ecd11642220bc9c8b4ff4157072c7fea4c6197d
|
|
| MD5 |
6a4e08c47d56370a062aa84d11c7c139
|
|
| BLAKE2b-256 |
5dd38a23607af12fccf426d074f8d90a48c412322a745757ea9d930d3a717547
|
Provenance
The following attestation bundles were made for weft_soc-0.1.0.tar.gz:
Publisher:
release.yml on hakursn/weft-soc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
weft_soc-0.1.0.tar.gz -
Subject digest:
532c136863548283c877a1b32ecd11642220bc9c8b4ff4157072c7fea4c6197d - Sigstore transparency entry: 2171247318
- Sigstore integration time:
-
Permalink:
hakursn/weft-soc@5a5863a7962b490ee97fb9e3f8565a5df1d81a81 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/hakursn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5a5863a7962b490ee97fb9e3f8565a5df1d81a81 -
Trigger Event:
push
-
Statement type:
File details
Details for the file weft_soc-0.1.0-py3-none-any.whl.
File metadata
- Download URL: weft_soc-0.1.0-py3-none-any.whl
- Upload date:
- Size: 29.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
440e733f1afe92509847804a2327dc4c9933d360b285bae538a41dcfec206237
|
|
| MD5 |
e6069cbc2f59888060205f88b4623173
|
|
| BLAKE2b-256 |
fe392d29a2e300f75a33256f2481fe6014cc260de0b6cab16c7af4f3e724e27a
|
Provenance
The following attestation bundles were made for weft_soc-0.1.0-py3-none-any.whl:
Publisher:
release.yml on hakursn/weft-soc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
weft_soc-0.1.0-py3-none-any.whl -
Subject digest:
440e733f1afe92509847804a2327dc4c9933d360b285bae538a41dcfec206237 - Sigstore transparency entry: 2171247328
- Sigstore integration time:
-
Permalink:
hakursn/weft-soc@5a5863a7962b490ee97fb9e3f8565a5df1d81a81 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/hakursn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5a5863a7962b490ee97fb9e3f8565a5df1d81a81 -
Trigger Event:
push
-
Statement type: