agentsclimarketplace

Hdl module design

Skill Midstall/claude-for-hardware/skills/hdl-module-design

Claude Code skills for hardware design, validation, and bring-up

Install
npx -y skills add Midstall/claude-for-hardware --skill hdl-module-design

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

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

SKILL.md

4.9 KB, as published. Nobody here has run it

HDL Module Design

Overview

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.

When to Use

  • Writing a new peripheral, datapath, control block, or reusable IP
  • A module takes a pile of bare int/String/bool constructor args
  • Configuration is validated late (at elaboration or simulation) instead of at construction
  • Domain logic is leaking into the CLI/generator wrapper instead of the library
  • Tests only exercise the top level, not the component

Skip for throwaway testbench glue or a one-line wire rename.

Design The Configuration First

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
}

Keep Logic In The Library

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.

Test Every Component, Exhaustively

This is going to silicon. A miss is a respin.

  • Mirror the source layout in tests. lib/components/fifo.dart -> test/components/fifo_test.dart, lib/config/... -> test/config/.... Anyone can find the test for a unit.
  • Test each component on its own, not only through the top level. Small units with clean boundaries are why this is possible.
  • Cover the config validation: assert the bad inputs actually throw.
  • Sweep the parameter space for parameterized modules: a representative set of widths/depths/modes, plus the boundaries (width 1, max depth, every enum value).
  • A failing check must fail. Never add an ignore/skip/ERROR_ON_X=false knob to make a violating design pass. Fix the design. See [[failures-should-fail]] in the silicon-grade-discipline skill.

Red Flags

SmellDo instead
8 positional int argsOne typed config object
mode == "fast"mode == Mode.fast (enum)
Width mismatch caught in simAssert it at config construction
Logic in the CLI commandLibrary method, CLI calls it
Only top-level testsOne test file per component, mirrored layout
skipDrc = true to get a passFix the design

Midstall House Style

  • ROHD/Dart: config classes use const constructors with final fields.
  • ISA-extension capabilities derive from the microcode/ISA description; privilege modes stay constructor flags. Derive, don't restate.
  • Build a reusable unit standalone with a golden test before wiring it in; it de-risks correctness and locks the interface.
  • No em dashes in code, comments, or docs. No emoji.
  • For ROHD/rohd_bridge/rohd_hcl sim and emission pitfalls see rohd-rtl-gotchas. See silicon-grade-discipline for the failures-should-fail and no-over-engineering rules this leans on.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.