bare-metal-bringup
Use when bringing up bare-metal or kernel code on a new architecture, SoC, or board (RISC-V, ARM, x86, ESP32) and it won't boot, hangs after boot, or faults…
Use when writing, refactoring, or deciding how to test an HDL module, component, or IP block (ROHD, Chisel, SpinalHDL, Verilog, VHDL) and you need it parameterized, validated, and covered by exhaustive tests rather than a one-off
$ npx -y skills add Midstall/claude-for-hardware --skill hdl-module-design --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/hdl-module-designContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when writing, refactoring, or deciding how to test an HDL module, component, or IP block (ROHD, Chisel, SpinalHDL, Verilog, VHDL) and you need it parameterized, validated, and covered by exhaustive tests rather than a one-off
name: hdl-module-design description: Use when writing, refactoring, or deciding how to test an HDL module, component, or IP block (ROHD, Chisel, SpinalHDL, Verilog, VHDL) and you need it parameterized, validated, and covered by exhaustive tests rather than a one-off
A hardware module is an interface plus an implementation. Get the interface and its configuration right and the implementation stays swappable, testable, and reusable across an FPGA and an ASIC.
**Core principle:** A module should declare exactly what it needs as typed configuration, validate it at build time, and be exhaustively testable in isolation. If you can't construct and test it without the rest of the SoC, the boundary is wrong.
Skip for throwaway testbench glue or a one-line wire rename.
Hardware bugs are expensive, so push errors as early as possible: ideally a type error, otherwise a build-time assertion, never a silent miscompile.
1. **One config object per module.** Group the parameters into an immutable config type with named, typed fields. The module takes the config, not a long positional arg list. 2. **Types, not strings.** Use enums for modes, kinds, and identifiers. `BusKind.axi4` not `"axi4"`. A typo becomes a compile error instead of a wrong build. 3. **Validate at construction.** Width relationships, power-of-two requirements, address-range overlaps, legal mode combinations: assert them when the config is built, with a message that names the offending field and value. Do not defer to simulation. 4. **Derive, don't duplicate.** If `addrWidth` is a function of `depth`, compute it. Don't make the caller pass both and hope they agree.
// ROHD-flavored, but the shape is language-neutral.
class FifoConfig {
final int depth;
final int width;
const FifoConfig({required this.depth, required this.width});
// build-time validation, names the bad field
void validate() {
if (depth <= 0 || (depth & (depth - 1)) != 0) {
throw ArgumentError('FifoConfig.depth must be a power of two, got $depth');
}
if (width <= 0) {
throw ArgumentError('FifoConfig.width must be positive, got $width');
}
}
int get addrWidth => depth.bitLength - 1; // derived, not passed in
}The module and its elaboration logic live in the library. The CLI, build script, or generator is a thin wrapper that parses args and calls library methods. This keeps the module usable by other code (other generators, tests, third parties) and keeps the surface testable without spawning a process.
If you find yourself reaching into a module's internals from the CLI, lift that into a library method.
This is going to silicon. A miss is a respin.
| Smell | Do instead | |-------|------------| | 8 positional `int` args | One typed config object | | `mode == "fast"` | `mode == Mode.fast` (enum) | | Width mismatch caught in sim | Assert it at config construction | | Logic in the CLI command | Library method, CLI calls it | | Only top-level tests | One test file per component, mirrored layout | | `skipDrc = true` to get a pass | Fix the design |
Claude Code skills for hardware design, validation, and bring-up. A plugin of focused skills that teach Claude how to do real hardware work: designing reusable HDL, integrating an SoC, bringing up FPGAs and bare-metal targets, building firmware boot chains,
Repo: Midstall/claude-for-hardware
Use when bringing up bare-metal or kernel code on a new architecture, SoC, or board (RISC-V, ARM, x86, ESP32) and it won't boot, hangs after boot, or faults…
Use when building or debugging a compiler backend, codegen, or assembler and you need to prove the generated machine code is correct by executing it on a real…
Use when verifying a hardware DUT (a CPU core, FPGA, or netlist) against a golden reference model, building coverage-guided fuzzing, or detecting where silicon…
Use when building or debugging a firmware and boot chain (RISC-V SBI, UEFI, ACPI, a bootloader handoff like Limine to an OS) or adding measured boot with a…
Use when loading a bitstream onto a physical FPGA and driving or observing it over JTAG or GPIO, especially bit-banged JTAG from a host like a Raspberry Pi, or…
Use when synthesizing RTL to an FPGA with yosys/nextpnr (ECP5/Lattice and similar), fighting area or routing congestion, measuring Fmax, deciding why a design…