# Gen Tb

> Generate a complete UVM testbench scaffold for a single IP from its spec documents (docx/pdf/md) and register table (xlsx/csv/md/IP-XACT). Use whenever the user asks to "generate a UVM tb", "build a verification environment", "scaffold a testbench", "create a UVC", "set up DV for this IP", or anything equivalent in Chinese ("帮我生成验证环境", "搭一个 tb", "做 UVM 环境", "做这个 IP 的验证"). Also trigger when the us…

- **Type:** Skill
- **Install:** `agentstack add skill-gokeshenzhen-gen-tb-skill-gen-tb-skill`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [gokeshenzhen](https://agentstack.voostack.com/s/gokeshenzhen)
- **Installs:** 0
- **Category:** [Data & Analytics](https://agentstack.voostack.com/c/data-and-analytics)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [gokeshenzhen](https://github.com/gokeshenzhen)
- **Source:** https://github.com/gokeshenzhen/gen-tb-skill

## Install

```sh
agentstack add skill-gokeshenzhen-gen-tb-skill-gen-tb-skill
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# gen-tb — UVM Testbench Scaffold Generator

## Purpose

Generate a directory-aligned UVM testbench for one IP from:

Built-in first-class buses: APB slave, AHB-Lite (slave or master),
AXI4-Lite (slave or master). Other single-channel request/response
buses (I2C, SPI, Wishbone, OBI, custom register buses, …) are handled
by a generic fallback that reuses the same layout, sim flow, and
`tb_api` surface — see §Scope below.

Inputs:

- behavioral spec: `*.docx`, `*.pdf`, `*.md`
- register table: `*.xlsx`, `*.csv`, markdown table, IP-XACT XML
- RTL in place, an external RTL path, or a generated stub

The result must compile, run `_sanity_test`, run
`_reg_access_test`, and provide two usage surfaces:

- DV persona: UVM tests, sequences, agent, monitor, RAL hooks
- DE persona: `tb_api::write/read/expect_reg` task-style BFM

## Scope

| Dimension | Built-in (high-quality scaffold) | Generic fallback | Planned |
|---|---|---|---|
| Bus | APB slave, AHB-Lite (slave or master), AXI4-Lite (slave or master) | any single-channel request/response bus the scaffold sub-agent can infer from spec + the three built-in exemplars (e.g. I2C, SPI, Wishbone, OBI, custom register buses) | AXI4 full |
| Simulator | VCS, Questa (vlog/vsim — static-only, see note), xrun (Cadence Xcelium) | VCS, Questa, xrun | — |
| Ref model | none, SV, C-DPI | none, SV, C-DPI | Python-DPI |
| Spec input | docx, pdf, md | docx, pdf, md | — |
| Reg input | xlsx, csv, md, IP-XACT | xlsx, csv, md, IP-XACT (optional — set `register_semantics: no` for non-register buses) | — |

Generic fallback is a best-effort path: directory layout and sim flow
stay authoritative, but the bus-shaped pieces (`_if.sv`, agent,
sequence library, `tb_api` body) are inferred per-IP by a constrained
scaffold sub-agent that pattern-matches on the three built-in
references. Tell the user up-front that scaffold correctness is lower
and the chance of an `unresolved.md` delivery is higher than in
built-in mode. Load `references/generic_bus.md` only when entering
this path.

AXI4 full (bursts/IDs/outstanding) is out of scope in both modes — it
must never be routed to generic. If the DUT has AXI ports, follow the
AXI4-full detector in Phase 1 and the mandatory question in Phase 2.
For DUTs that expose AXI signals but use only single-beat transfers,
generate the AXI4-Lite environment with a monitor-side assertion that
`AWLEN == 0 && ARLEN == 0`, so any later burst use fails loud at sim
time rather than relying on user review.

Do not use this skill for debugging an existing UVM environment, formal
verification, gate-level sim, DFT, or a multi-master SoC subsystem.

## Pipeline

Each phase writes audit artifacts under `/work/_gen_audit/`.
Do not collapse phases; resumability and auditability are part of the
deliverable.

1. Discover: identify IP, spec, regs, RTL, optional external VIP
2. Intake: ask only unresolved questions
3. Normalize: produce `registers.yaml`, `behavior.md`, `parse_report.md`
4. Scaffold: write the generated tree
5. Compile-fix: run compile and use a constrained sub-agent if needed
6. Sanity: run mandatory tests and runtime-fix loop if needed
7. Hand-off: write `CLAUDE.md`, `unresolved.md`, and concise summary

### Pipeline Hooks (Optional)

After each phase finishes writing its audit artifacts, call:

```bash
python3 scripts/hooks.py  
```

with `` ∈ `{discover, intake, normalize, scaffold, compile_fix,
sanity, handoff}`. The script looks for
`/.gen_tb_hooks/[.strict].{py,sh}` and is a no-op when
absent (zero cost in the common case). Non-strict hook failures are
logged to `work/_gen_audit/hooks/.log` and do not block the
pipeline; `.strict.` hooks abort the phase on non-zero exit. Hooks
receive a JSON payload on stdin and `GEN_TB_PHASE` / `GEN_TB_IP_ROOT` /
`GEN_TB_AUDIT_DIR` in env. Do not invoke hooks before audit artifacts
for the phase are on disk.

## Phase 1: Discover

### IP Selection

Pick the IP root in this order:

1. Explicit IP name/path from the user
2. Current directory if its basename looks like an IP name
3. The only child directory containing spec files
4. Otherwise ask the user to choose

Show the selected IP name and path once so the user can correct it.

### Spec And Registers

Search `spec/`, `doc/`, `docs/`, then IP root. Classify:

- register table: `*reg*table*.xlsx/csv`, `*regs*.xlsx/csv`, IP-XACT XML
- behavior spec: large `*.pdf`, `*.docx`, `*spec*.md`
- markdown tables that look like regs: confirm if ambiguous

Do not ingest README, license, unrelated datasheets, draft/old/bak files.

### RTL

Prefer an existing filelist. Otherwise scan `rtl/`, `src/`, `design/`,
`hdl/`, and `/` for RTL, excluding tb/test/sim/bench paths.
If no RTL exists, generate a stub only when the user confirms.

Infer top module using AST tooling if available; regex inference is
medium confidence. If top is ambiguous, ask. Record exact APB / AHB /
AXI4-Lite signal names and widths in `rtl_discovery.yaml`; never
normalize case. For AHB-Lite and AXI4-Lite, also record which side of
the bus the DUT sits on (`bus_direction: slave|master`) — slave is the
default and means the TB drives a master BFM; master means the TB
provides a memory-backed slave responder.

For buses that fall through to generic mode, `rtl_discovery.yaml`
does **not** record `bus_direction`. The direction is collected in
Phase 2 into `bus_handshake.yaml.direction` and that is the single
source of truth for generic mode.

For details, load `references/rtl_discovery.md` and
`references/rtl_stub.md`.

### Bus Classification

After signal recording, classify the bus:

1. If the top's port set matches the APB / AHB-Lite / AXI4-Lite
   signature, set `bus_protocol` accordingly. **Unchanged path.**
2. **AXI4-full detector.** If any of `awlen | arlen | awburst |
   arburst | awid | arid` is present with width > 0, set
   `axi_full_signature: true` in `rtl_discovery.yaml`. The Phase 2
   mandatory question below decides whether to refuse or degrade
   to AXI4-Lite. An AXI signal set must never be routed to
   `bus_protocol: generic`.
3. Otherwise set `bus_protocol: unknown` and emit a
   `candidate_signals:` block (the request/response-looking port
   group) into `rtl_discovery.yaml`. Do not guess a name — the
   bus name is collected in Phase 2.

### Existing Bus VIP

If the user says they already have an APB, AHB, or AXI4-Lite VIP, ask
for only:

- `_vip_path`
- desired reuse level: `import_only` or `drive_with_vip`

Use:

```yaml
bus_protocol: apb                  # or ahb, axi_lite
apb_vip_source: reuse_my_vip       # or ahb_vip_source / axi_lite_vip_source
apb_vip_path:                # or ahb_vip_path / axi_lite_vip_path
apb_vip_reuse_level: import_only   # or ahb_vip_reuse_level / axi_lite_vip_reuse_level; default
```

`import_only` means scaffold imports the VIP into the compile tree and
keeps built-in tests on `tb_api`. `drive_with_vip` means Phase 5 must
also generate/adapt glue so the user's VIP can drive a minimal bus
read/write smoke sequence — **not implemented in v1**; `scaffold.py`
refuses `drive_with_vip` and the skill must default to `import_only`
or hand-author the VIP-driven smoke test post-hoc. Do not guess
third-party VIP APIs in Phase 4. For `import_only`, scaffold may skip
vendor `*_test_pkg.sv` files that only serve the VIP's standalone
harness.

Load `references/apb_external_vip.md`, `references/ahb_external_vip.md`,
or `references/axi_lite_external_vip.md` before implementing or fixing
external VIP reuse.

At phase end, if `/.gen_tb_hooks/` exists, run
`python3 scripts/hooks.py discover `.

## Phase 2: Intake

Ask unresolved items in small batches. Questions to ask only when not
already known.

**Preset bundles are allowed** (e.g. "Default config" / "Add C-DPI" /
"VCS + xrun"), but every preset menu must satisfy:

1. The currently supported simulators (`vcs`, `questa`, `xrun`) must
   all appear at least once across the offered presets, or be reachable
   via an explicit "Customize simulators" / "Type something" path that
   lists them. Never present a simulator-related preset that names only
   a subset (e.g. listing "VCS / xrun" while omitting Questa) — it
   misleads the user into thinking the missing one is unsupported.
2. The same rule applies to any other dimension with >1 first-class
   value (bus protocol, refmodel language). If a preset hides a
   first-class option, the menu must include a visible "Customize"
   escape that surfaces the full set.
3. The AXI4-full mandatory question (see below) is **never** allowed
   inside a preset bundle — it must be its own AskUserQuestion turn.

Fields to ask about when not already pinned by Phase 1:

- RTL state: found, external path, generated stub, none
- bus protocol: APB, AHB, AXI4-Lite, or `generic` (when Phase 1 set
  `bus_protocol: unknown`)
- bus direction (AHB-Lite, AXI4-Lite, generic): DUT is slave (default) or master
- bus VIP source: generate fresh, reuse existing VIP
- external VIP reuse level: import only, drive with VIP
- reference model language: none, SV, C-DPI (Python-DPI schema exists but is
  not yet emitted — see `references/refm_dpi.md`)
- clock/reset: `pclk/presetn`, `hclk/hresetn`, or `aclk/aresetn` frequency, polarity, reset cycles
- UVM version: default 1.2 unless user specifies otherwise
- **simulator toolchain** (multi-select): `vcs`, `questa`, `xrun`.
  Default `[vcs]` when unanswered. Record in `intake.yaml` as
  `simulators: [vcs]` / `[vcs, questa]` / `[vcs, xrun]` /
  `[vcs, questa, xrun]` / etc. At least one must be selected.
  Per-sim emission:
  - `vcs` → `script/makefile` (canonical `make all SV_CASE=`).
  - `questa` → `script/makefile_questa`
    (`make -f makefile_questa all SV_CASE=`). **Static-only** —
    gen-tb has no Questa install to validate against; tell the user to
    verify locally before trusting it in CI.
  - `xrun` → `script/makefile_xrun`
    (`make -f makefile_xrun all SV_CASE=`).
  When `vcs` is not selected, `script/makefile` becomes a thin shim
  that `include`s whichever sim-specific makefile is present, so the
  canonical `make all SV_CASE=...` still works. `scripts/compile_and_sanity.py`
  drives VCS by default; for questa-only or xrun-only configurations,
  run the mandatory tests with `make -f makefile_ all SV_CASE=`
  manually. Recommended user-facing wording:
  *"Which simulators should I generate makefiles for? VCS / Questa /
  xrun (multi-select; default VCS)."*
- **tcsh/csh setup helper**: default no. If the user uses tcsh/csh,
  record `emit_setup_csh: true` in `intake.yaml`; scaffold still emits
  `script/setup.sh` and additionally emits `script/setup.csh`. Do not
  infer this from `$SHELL`; generated trees may be used by other users
  or CI shells.
- address width: `paddr_width`, `haddr_width`, or `axi_addr_width`, default 12
- endianness for multi-word arrays
- coverage: enabled or skipped
- required extra smoke tests

### AXI4-full Mandatory Question

When `rtl_discovery.yaml` has `axi_full_signature: true`, ask exactly:
*"Does this DUT use bursts (>1 beat), IDs, or outstanding?"* This
question is mandatory and cannot be skipped. Record the answer in
`intake.yaml` as `axi4_full_features: none` (No) or
`axi4_full_features: present` (Yes) — `scaffold.py` refuses to run
without it.

- Yes (`axi4_full_features: present`) → hard refuse. Write
  `unresolved.md` pointing to planned AXI4-full work and exit. Do not
  enter Phase 3.
- No (`axi4_full_features: none`) → route to the built-in AXI4-Lite
  path. Phase 4 must emit a monitor-side assertion that
  `AWLEN == 0 && ARLEN == 0`, so any later burst use fails loud at
  sim time.
- Unanswered / skipped → treat as Yes (refuse). `scaffold.py` exits
  FATAL when `axi_full_signature: true` and the intake key is absent.

### Generic Bus Intake Sub-Batch

When `bus_protocol` resolves to `generic`, collect the structured
handshake description into `work/_gen_audit/bus_handshake.yaml`:

```yaml
bus_name: 
direction: slave | master
clock: { name: , freq_mhz:  }
reset: { name: , polarity: low|high, cycles:  }
addr:  { port: , width:  } | null     # null = non-addressed
data:  { write_port: , read_port: , width:  }
handshake:
  kind: req_ack | valid_ready | strobe | custom
  req:   
  ack:   
  extra: [  ]
burst: none | simple_incr
register_semantics: yes | no
notes: |
  Free-form. Primary handshake hint to the scaffold sub-agent.
```

Confirm `register_semantics` explicitly. `no` means RAL and
`_reg_access_test` are not generated and Phase 6 degrades to
`_responder_smoke_test`.

All generated tests must be named `__test`.

Every question turn must include an abort/restart option. Save partial
answers to `work/_gen_audit/intake.yaml` and `bus_handshake.yaml`, and
resume from them if present.

At phase end, if `/.gen_tb_hooks/` exists, run
`python3 scripts/hooks.py intake `.

## Phase 3: Normalize

Create:

```text
work/_gen_audit/spec_normalized/registers.yaml
work/_gen_audit/spec_normalized/behavior.md
work/_gen_audit/spec_normalized/parse_report.md
```

Never proceed to Phase 4 without valid `registers.yaml`, **except**
when `bus_handshake.yaml.register_semantics == no` in generic mode —
that case has no register table by design, and `registers.yaml` is
optional. `behavior.md` and `parse_report.md` are still required in
all cases. Missing behavior parsers may degrade to warnings, but a
missing/unparseable register table is blocking outside the
`register_semantics: no` exception.

Field-level reset values win over register-level reset values. Emit
warnings for unparseable offsets, widths, bit ranges, PDF tables,
ambiguous aliases, and contradictions. The user must be told to read
`parse_report.md`.

Load `references/spec_parsing.md` and
`references/registers_yaml_schema.md` for schemas and parser rules.

At phase end, if `/.gen_tb_hooks/` exists, run
`python3 scripts/hooks.py normalize `.

## Phase 4: Scaffold

Use `scripts/scaffold.py` with the audit inputs. The generated layout is
fixed; load `references/directory_layout.md` for the authoritative tree.

Key scaffold rules:

- write `script/design.f`, not `rtl/design.f`
- write lowercase `script/makefile`
- write `script/tb.f` for tb-side sources
- always write bash-compatible `script/setup.sh`; when
  `emit_setup_csh: true`, also write `script/setup.csh`
- never copy or modify user RTL
- if `_vip_source: generate_fresh`, emit `tb/_agt_top/`
- if `reuse_my_vip`, emit `tb/external_vip.f` and skip fresh agent files
- external VIP reuse is supported only for built-in buses; generic
  mode always generates fresh (no `generic_vip_source: reuse_my_vip`)
- keep `tb_api` generated in all modes
- generate `top/_tb_top.sv`, `tb/_if.sv`, tests, audit
- RAL is generated when the configuration has register semantics: i.e.
  built-in slave direction, or generic slave direction with
  `register_semantics: yes`. Master direction in either mode skips
  RAL; generic `register_semantics: no` skips RAL.

For APB generation, load `references/apb.md`. For AHB generation, load
`references/ahb.md`. For AXI4-Lite generation, load
`references/axi_lite.md`. For external VIP reuse, load
`references/apb_external_vip.md`, `references/ahb_external_vip.md`, or
`references/axi_lite_external_vip.md`.
For top wiring, load
`references/top_sv.md`. For Makefile, load
`references/makefile_contract.md`. For `tb_api`, load
`references/tb_api.md`. For DPI, load `references/refm_dpi.md`.

### Generic Bus Branch

When `bus_protocol == generic`:

1. `scripts/scaffold.py` emits the bus-agnostic skeleton it already
   knows: top tree, `script/design.f`, lowercase `script/makefile`,
   `script/tb.f`, test directory, audit dirs, empty
   `tb/_agt_top/` with placeholder files, and a stub
   `tb/_if.sv` containing only the ports from
   `bus_handshake.yaml`. RAL is generated iff
   `register_semantics: yes`.
2. Invoke the **scaffold sub-agent** defined in
   `references/sub_agent_generic_scaffold.md`. Inputs:
   - `references/generic_bus.md` (contract)
   - `references/apb.md`, `ahb.md`, `axi_lite.md` (exemplars)

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [gokeshenzhen](https://github.com/gokeshenzhen)
- **Source:** [gokeshenzhen/gen-tb-skill](https://github.com/gokeshenzhen/gen-tb-skill)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-gokeshenzhen-gen-tb-skill-gen-tb-skill
- Seller: https://agentstack.voostack.com/s/gokeshenzhen
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
