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 optimizing RTL microarchitecture for area or clock frequency (Fmax), a design is too big to fit or too slow to meet timing, a wide multiply or barrel shifter is the critical path, or a "compute everything and select" datapath is too large
$ npx -y skills add Midstall/claude-for-hardware --skill rtl-area-timing --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/rtl-area-timingContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when optimizing RTL microarchitecture for area or clock frequency (Fmax), a design is too big to fit or too slow to meet timing, a wide multiply or barrel shifter is the critical path, or a "compute everything and select" datapath is too large
name: rtl-area-timing description: Use when optimizing RTL microarchitecture for area or clock frequency (Fmax), a design is too big to fit or too slow to meet timing, a wide multiply or barrel shifter is the critical path, or a "compute everything and select" datapath is too large
Making RTL smaller or faster is a sequence of structural decisions, each justified by a measurement. The wins are rarely where intuition points: the giant is often a structure you didn't think of (a "ROM" that is really 94k flops), and the critical path is usually one specific primitive, not "logic depth" in general.
**Core principle:** Diagnose with data, change one structure, re-measure. Optimize the actual critical path or the actual giant, and stop the moment it stops being the bottleneck. Guessing wastes builds and can place worse.
This is the RTL-technique companion to `fpga-synthesis-fit` (the tool methodology for measuring). Measure there, transform here.
A single-cycle NxN multiply (64x64) maps to DSP tiles plus a long partial-product carry chain, and that chain is usually the critical path.
Registering only the multiply's OUTPUT does not break the internal carry chain; the operands-to-output path is still essentially the whole multiply. You must pipeline INTERNALLY: decompose into smaller products (four 32x32), register the partial products, then sum the shifted partials in a second registered stage. Make the op multi-cycle with a small stall counter. On ECP5 this took a 64x64 from about 33 MHz to about 47 MHz.
Registering the multiply INPUTS too gave diminishing returns and placed worse. Stop once the multiply leaves the critical path; re-read the report to confirm.
Pipelining a multiply buys Fmax; SERIALIZING it buys area. Replace a single-cycle 64x64 multiply with a multi-cycle shift-add (radix-2^k, one small `wide * chunk` product per step reused across steps) and the whole partial-product reduction tree disappears, halving the DSP count. The same shape works for divide: one iterative restoring shift-subtract divider replaces eight combinational div/rem trees (which were 60% of an SoC) with a small datapath plus a stall counter, on the same resident-mopStep stall pattern as a multi-cycle FP op. On an area-first, latency-tolerant core this is close to free, and the serialized operator usually sits on the critical path too, so it buys Fmax as a side effect.
Correction to a common misread: a multiplier CAN be a post-pack area lever even when it looks tiny pre-pack. Its partial-product mux cells (PFUMX, L6MUX21) hide in the pre-pack LUT4 count but pack into slices post-pack, so an "only 843 LUT4, not worth it" judgement made pre-pack is wrong against `TRELLIS_COMB`. Measure post-pack (see the metric trap in `fpga-synthesis-fit`).
A reusable peripheral sized by its default can dominate area on a small SoC. An interrupt controller defaulting to 32 sources, instantiated on an SoC with 3, builds a 32-wide priority and claim mux tree: one such block was 917 cells, about 16% of a small design, and dropped to 133 cells when sized to the real source count (`sources: devices.length + 1`). Audit every parameterized block's effective size against what the instance truly needs before hand-trimming RTL; the default is often the biggest single win and the easiest.
A microcoded exec or decoder that computes all handler datapaths in parallel and muxes the winner by opcode builds every handler's logic. Real area wins:
`addr >> (base + k*stride)` is a 64-bit barrel shifter plus a multiply. If it extracts a FIXED field per `k` (a page-table VPN[level] slice), replace it with a mux of fixed slices.
But on ECP5 this can be post-pack neutral: barrel shifters and mux trees pack to similar slice counts. It reduces pre-pack LUT4 but may not move `TRELLIS_COMB`. Measure post-pack before believing the win (see the metric trap in `fpga-synthesis-fit`).
Sign-extension from W to 2W bits is monotonic for BOTH signed and unsigned W-bit ordering (it maps the two halves of the W-bit range to two ordered ranges in the wider unsigned space). So one comparator on sign-extended operands computes signed min/max AND unsigned minu/maxu, useful for AMOs and ALUs.
Verify the stored RESULT width: compute at XLEN but store the low `size.bits`, and match the surrounding code's sign-vs-zero extension of the stored value. A test once caught a sign/zero-extend mismatch on the store side here.
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…