From rtl-agent-team
Guides UVM testbench development in SystemVerilog with standards for naming conventions, class hierarchy, factory patterns, sequences, sequencers, TLM ports, and coverage integration.
npx claudepluginhub babyworm/rtl-agent-team --plugin rtl-agent-teamThis skill uses the workspace's default tool permissions.
<Purpose>
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
<Use_When>
<Do_Not_Use_When>
rtl-p5s-func-verify skillsystemverilog-assertion skillsystemverilog skill
</Do_Not_Use_When><Why_This_Exists> UVM is an industry-standard verification methodology, but its high degree of freedom easily leads to inconsistent code. Following consistent naming conventions, class structure, and factory usage patterns ensures:
<Execution_Policy>
templates/uvm-env-template.sv as the starting point for new environmentsexamples/uvm-smoke-test-example.sv for basic smoke test structureuvm_component_utils / uvm_object_utils)| Type | Pattern | Example |
|---|---|---|
| Agent | {proto}_agent.sv | axi_agent.sv |
| Driver | {proto}_driver.sv | axi_driver.sv |
| Monitor | {proto}_monitor.sv | axi_monitor.sv |
| Sequencer | {proto}_sequencer.sv | axi_sequencer.sv |
| Sequence Item | {proto}_seq_item.sv | axi_seq_item.sv |
| Sequence | {proto}_{name}_seq.sv | axi_write_seq.sv |
| Scoreboard | {module}_scoreboard.sv | cabac_scoreboard.sv |
| Environment | {module}_env.sv | cabac_env.sv |
| Test | {module}_{name}_test.sv | cabac_smoke_test.sv |
| Package | {module}_tb_pkg.sv | cabac_tb_pkg.sv |
| Top | tb_{module}_top.sv | tb_cabac_top.sv |
| Target | Pattern | Example |
|---|---|---|
| Agent | {proto}_agent | axi_agent |
| Driver | {proto}_driver | axi_driver |
| Monitor | {proto}_monitor | axi_monitor |
| Sequencer | {proto}_sequencer | axi_sequencer |
| Sequence Item | {proto}_seq_item | axi_seq_item |
| Sequence (base) | {proto}_base_seq | axi_base_seq |
| Sequence (specific) | {proto}_{name}_seq | axi_write_burst_seq |
| Scoreboard | {module}_scoreboard | cabac_scoreboard |
| Environment | {module}_env | cabac_env |
| Test (base) | {module}_base_test | cabac_base_test |
| Coverage | {module}_coverage | cabac_coverage |
m_prefix rule: UVM class member handles usem_prefix per industry convention. This is separate from the RTLu_prefix rule and applies to UVM TBs only.
// Instance name matches the variable name
m_driver = axi_driver::type_id::create("m_driver", this);
m_monitor = axi_monitor::type_id::create("m_monitor", this);
m_seqr = axi_sequencer::type_id::create("m_seqr", this);
uvm_test
└── cabac_base_test
└── cabac_smoke_test
└── cabac_random_test
uvm_env
└── cabac_env
├── axi_agent (m_axi_agt)
│ ├── axi_driver (m_driver)
│ ├── axi_monitor (m_monitor)
│ └── axi_sequencer (m_seqr)
├── cabac_scoreboard (m_scoreboard)
└── cabac_coverage (m_coverage)
All UVM components/objects must be registered with the factory:
class axi_driver extends uvm_driver #(axi_seq_item);
`uvm_component_utils(axi_driver)
function new(string name = "axi_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
// ...
endclass
class axi_seq_item extends uvm_sequence_item;
`uvm_object_utils(axi_seq_item)
function new(string name = "axi_seq_item");
super.new(name);
endfunction
// ...
endclass
| Phase | Purpose | Notes |
|---|---|---|
build_phase | Component create, config_db get | Only create here |
connect_phase | TLM port connections | After build completes |
end_of_elaboration_phase | Final structure check | Optional |
run_phase | Simulation execution | raise/drop objection required |
extract_phase | Collect results | Optional |
check_phase | pass/fail determination | Optional |
report_phase | Report results | Scoreboard summary |
task cabac_base_test::run_phase(uvm_phase phase);
phase.raise_objection(this, "Test started");
// ... test body (start sequences)
phase.drop_objection(this, "Test completed");
endtask
| Port Type | Direction | Purpose |
|---|---|---|
uvm_analysis_port | Monitor → Scoreboard/Coverage | Broadcast (1:N) |
uvm_seq_item_pull_port | Driver ↔ Sequencer | Auto-connected |
uvm_analysis_imp | Scoreboard receiver | Must implement write() |
// Monitor: analysis port declaration and usage
class axi_monitor extends uvm_monitor;
uvm_analysis_port #(axi_seq_item) m_ap;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
m_ap = new("m_ap", this);
endfunction
task run_phase(uvm_phase phase);
// ... capture transaction
m_ap.write(txn); // broadcast to all subscribers
endtask
endclass
// Scoreboard: analysis imp declaration
class cabac_scoreboard extends uvm_scoreboard;
`uvm_analysis_imp_decl(_input)
`uvm_analysis_imp_decl(_output)
uvm_analysis_imp_input #(axi_seq_item, cabac_scoreboard) m_input_imp;
uvm_analysis_imp_output #(axi_seq_item, cabac_scoreboard) m_output_imp;
function void write_input(axi_seq_item txn);
// enqueue expected
endfunction
function void write_output(axi_seq_item txn);
// compare with expected
endfunction
endclass
// Test → Agent: pass virtual interface (build_phase)
uvm_config_db #(virtual axi_if)::set(this, "m_env.m_axi_agt*", "vif", m_vif);
// Agent: retrieve virtual interface (build_phase)
if (!uvm_config_db #(virtual axi_if)::get(this, "", "vif", m_vif))
`uvm_fatal("NO_VIF", "Virtual interface not set for agent")
* supported)uvm_fatal is mandatoryclass cabac_coverage extends uvm_subscriber #(axi_seq_item);
`uvm_component_utils(cabac_coverage)
covergroup cg_transaction;
cp_cmd: coverpoint m_txn.cmd { bins read = {0}; bins write = {1}; }
cp_size: coverpoint m_txn.size { bins sizes[] = {1, 2, 4, 8}; }
cross cp_cmd, cp_size;
endgroup
function new(string name, uvm_component parent);
super.new(name, parent);
cg_transaction = new();
endfunction
function void write(axi_seq_item t);
m_txn = t;
cg_transaction.sample();
endfunction
endclass
| Anti-Pattern | Problem | Fix |
|---|---|---|
| Not registered with factory | Cannot override/reuse | Add uvm_*_utils to all classes |
| Objection in driver | Phase control confusion | Only raise/drop in test |
| Ignoring config_db get failure | Null pointer crash | Handle with uvm_fatal |
| Direct DUT access from sequence | Destroys reusability | Use sequencer→driver path only |
| Hard-coded hierarchy path | Destroys portability | Use config_db wildcard |
#delay in run_phase | Destroys portability | Use @(posedge vif.sys_clk) |
<Tool_Usage> This skill is not executed directly. It is referenced by agents that generate UVM environments (e.g., testbench-dev). Agents should follow the conventions defined here. </Tool_Usage>
Factory registration, correct naming, config_db usage, analysis port: ```systemverilog class axi_agent extends uvm_agent; `uvm_component_utils(axi_agent) axi_driver m_driver; axi_monitor m_monitor; axi_sequencer m_seqr;function void build_phase(uvm_phase phase); super.build_phase(phase); m_driver = axi_driver::type_id::create("m_driver", this); m_monitor = axi_monitor::type_id::create("m_monitor", this); m_seqr = axi_sequencer::type_id::create("m_seqr", this); endfunction endclass
</Good>
<Bad>
No factory usage, hard-coded, direct new:
```systemverilog
class my_agent extends uvm_agent;
// WRONG: no uvm_component_utils
my_driver drv;
function void build_phase(uvm_phase phase);
drv = new("drv", this); // WRONG: bypasses factory
endfunction
endclass
<Escalation_And_Stop_Conditions>
<Final_Checklist>
uvm_component_utils / uvm_object_utils)uvm_fatal on config_db get failure{proto}_agent, {proto}_driver, m_ prefix instances