| name | dv-sequences |
| description | Design Verification skill (S6) that generates UVM sequences, virtual sequences,
and UVM test classes from a DV testplan (Excel or JSON) and an existing UVM
testbench (described by dv_tb_data.json from S5, or by scanning the dv/ tree).
Use this skill whenever a user wants to:
- Generate UVM sequences and tests from a DV testplan (S2 Excel or JSON)
- Create directed test sequences for specific testplan rows
- Create randomized virtual sequences for coverage-driven tests
- Generate per-VIP protocol sequences (write, read, burst, error injection)
- Generate UVM test classes with plusargs, cfg constraints, and vseq execution
- Generate a single testcase interactively from a natural-language description
- Run /dv-sequences or S6 in the DV end-to-end flow
Trigger on: "generate sequences", "generate tests", "dv-sequences", "/dv-sequences",
"create testcases", "write sequence for", "S6", "generate test from testplan",
"create directed test", "create random test", "generate vseq", "write a test that"
|
DV Sequences Generator — S6
You are acting as a senior DV architect with 20+ years of UVM experience. Your output
is production-quality SystemVerilog: sequences and test classes that plug directly into
the UVM testbench generated by S5 (or any compatible existing testbench). Every
generated file must compile clean, follow UVM coding guidelines, and embed Checker ID
display messages at every verification point.
Step 0 — Check Environment (ALWAYS run first)
python3 <REPO_ROOT>/skills/common/scripts/check_environment.py --skill s6 --install
Common scripts for this skill:
<REPO_ROOT>/skills/common/scripts/
├── check_environment.py # dependency checker
├── generate_sequences.py # S6 file generator (sequences + tests)
└── generate_tb_scaffold.py # S5 generator (referenced, not run by S6)
Step 1 — Locate Testbench Data (MANDATORY — STOP if missing)
S6 requires a testbench description to generate compatible code.
Search in this order:
<PROJECT_ROOT>/dv/dv_tb_data.json — S5 output (preferred)
<OUTPUT_DIR>/dv_tb_data.json
- Any
dv_tb_data.json the user provides
If dv_tb_data.json is NOT found:
============================================================
⛔ S6 STOPPED — Testbench data not found
============================================================
dv_tb_data.json was not found in the expected locations.
This file is generated by S5 (dv-tb-scaffold) and describes
the testbench structure S6 needs to generate compatible code.
Options:
1. Run /dv-tb-scaffold first to generate the testbench and
dv_tb_data.json, then re-run /dv-sequences.
2. Provide the path to an existing dv_tb_data.json manually.
3. Provide the path to an existing dv/ directory so S6 can
scan it — S6 will ask targeted questions to fill gaps.
Please choose an option (1/2/3):
============================================================
Wait for user response. If option 3, proceed to Step 1b.
Step 1b — Scan Existing Testbench (option 3 only)
Scan the provided dv/ directory. Find:
*_env.sv → extract env class name, agent handles, scoreboard handle
*_virtual_seqr.sv → extract sequencer handle names
*_env_cfg.sv → extract cfg class name, VIF handles, RAL handle
*_base_test.sv → extract base test class name
*_agent_pkg.sv files → extract VIP/protocol names
Ask the following in a single message:
I found the following in your dv/ directory:
Env: <env_class_name>
Virtual seqr: <vseqr_class_name>
Env cfg: <cfg_class_name>
Base test: <base_test_class_name>
VIPs detected: <list>
Please confirm or correct:
1. Is this the correct project name? [<inferred_name>]
2. Which interface is used for register access (RAL bus)? [<inferred or ??>]
3. Is there a RAL reg_block? If yes, what is the class name? [<inferred or ??>]
4. Where is your testplan? (path to testplan.xlsx or testplan_data.json) [??]
Build a synthetic dv_tb_data.json from these answers and proceed.
Step 2 — Locate Testplan
Search in this order:
<PROJECT_ROOT>/dv/testplan.xlsx (S2 Excel output)
<PROJECT_ROOT>/dv/testplan_data.json (S2 JSON output)
- Path provided by user
If neither found:
Ask: "Please provide the path to your testplan (testplan.xlsx or testplan_data.json).
Alternatively, describe the testcase you want to generate."
- If user provides a path → use it
- If user provides a description → go directly to Step 6 (Interactive Individual)
Step 3 — Parse Inputs and Show Summary
Parse dv_tb_data.json:
project_name → used for class prefix
unique_vips[] → each has: vip_name, protocol, data_width, addr_width,
agent_name (in env), sequencer_name (in virtual_seqr)
ral → reg_block_class, adapter_class, base_addr, registers[]
env → env_class, env_cfg_class, virtual_seqr_class
base_test → base_test_class
Parse testplan (Excel preferred, JSON fallback):
Print summary:
============================================================
S6 Input Summary — <PROJECT_NAME>
============================================================
Testbench: <dv_tb_data.json path>
Testplan: <path> (<N> rows parsed)
VIPs: <vip1> (<proto1>), <vip2> (<proto2>), ...
RAL: <reg_block_class> (<N> registers)
------------------------------------------------------------
Tests to generate:
Directed : N
Random : N
Neg/Corner/Stress: N
Total : N
------------------------------------------------------------
Milestones: DV-I=N DV-C=N DV-F=N
============================================================
Step 4 — Choose Generation Mode
Ask the user:
============================================================
Generation Mode
============================================================
[1] Generate ALL testcases (entire testplan)
[2] Generate by milestone (DV-I / DV-C / DV-F)
[3] Generate specific testcase(s) by name or number
[4] Generate individual testcase interactively (describe it)
[5] Generate only agent sequences (no test classes)
Enter choice:
============================================================
Wait for response:
1 → set filter=all, go to Step 5
2 → ask which milestone(s), set filter, go to Step 5
3 → ask for name/numbers from the summary list, go to Step 5
4 → go to Step 6 (Interactive Individual)
5 → go to Step 5, skip test class generation
Step 5 — Bulk Generation via Script
5a — Write intermediate JSON
Write /tmp/<project>_sequences_input.json:
{
"project_name": "<name>",
"dv_root": "<abs path to dv/>",
"tb_data": { <full contents of dv_tb_data.json> },
"testplan_rows": [
{
"feature": "...",
"subfeature": "...",
"brief_description": "...",
"verification_type": "directed|random|neg|stress|corner",
"test_name": "<extracted from verification_type>",
"testcase_description": "...",
"checker_id": "CHK_...",
"checker_type": "Procedural|Assertion|Both",
"assertion_code": "...",
"milestone": "DV-I|DV-C|DV-F"
}
],
"filter": "all | DV-I | DV-C | DV-F | <test_name_list>"
}
5b — Run generator script
python3 <REPO_ROOT>/skills/common/scripts/generate_sequences.py \
--input /tmp/<project>_sequences_input.json \
--output <dv_root>
The script generates (see Appendix: Generated File Layout).
5c — If Bash unavailable
Write the JSON file using the Write tool, then instruct the user to run the script manually.
Step 6 — Interactive Individual Testcase Generation
This mode generates a single sequence + test class based on a user description.
Always ask ALL clarifying questions in one message before generating anything.
When a user says something like "write a test that writes CTRL.MODE=2 and checks STATUS.DONE",
analyze and ask any that are unclear:
============================================================
Individual Testcase — Clarification
============================================================
I'll generate a directed testcase for: "<user description>"
Please confirm / fill in the blanks:
1. Test name: [suggested: <proj>_ctrl_mode_write_test]
(snake_case, no spaces)
2. Primary operation: Register access via RAL / Protocol sequence / Both
[inferred: RAL write to CTRL, then poll STATUS]
3. Agents involved: <list inferred from description>
Correct? Add or remove any?
4. DUT config (env_cfg fields to set before test):
e.g. num_txns=1, sb_enable=1. Anything specific? [default: sb_enable=1]
5. Pass criteria / what must be checked:
[inferred: STATUS.DONE == 1 after CTRL.MODE write]
6. Any specific plusargs for this test?
e.g. +VERBOSE, +NUM_TXNS=N [default: none beyond base_test plusargs]
7. Milestone: [DV-I / DV-C / DV-F — inferred: DV-I]
8. Error injection expected? (negative test?) [No]
Reply with corrections. Type OK to accept all defaults.
============================================================
Wait for response, then generate:
- Agent sequences (any new operations needed, skipping existing files)
- Virtual sequence:
dv/sequences/<proj>/<test_name>_vseq.sv
- Test class:
dv/tests/<proj>_<test_name>_test.sv
Print the files inline (do NOT call the script — write them directly with Write tool).
Step 7 — Generated File Anatomy
7a — Agent sequences
Location: dv/sequences/<PROTOCOL>/
One file per operation per VIP. Skip if file already exists (safe_write).
Standard operations generated per protocol:
| Protocol | Operations generated |
|---|
| APB | apb_write_seq, apb_read_seq, apb_poll_seq |
| AHB / AHB-Lite | ahb_write_seq, ahb_read_seq, ahb_burst_seq |
| AXI4 | axi4_write_seq, axi4_read_seq, axi4_burst_write_seq, axi4_burst_read_seq |
| AXI4-Stream | axi4s_send_seq, axi4s_recv_seq |
| SPI | spi_write_seq, spi_read_seq, spi_transfer_seq |
| I2C | i2c_write_seq, i2c_read_seq |
| UART | uart_send_seq, uart_recv_seq |
| TileLink | tl_get_seq, tl_put_seq, tl_atomic_seq |
Each agent sequence:
// FILE: dv/sequences/<PROTOCOL>/<proto>_<op>_seq.sv
class <proto>_<op>_seq extends <proto>_base_seq;
`uvm_object_utils(<proto>_<op>_seq)
// Randomizable stimulus fields
rand logic [DATA_WIDTH-1:0] data;
rand logic [ADDR_WIDTH-1:0] addr;
function new(string name = "<proto>_<op>_seq");
super.new(name);
endfunction
task body();
<proto>_seq_item req;
req = <proto>_seq_item::type_id::create("req");
start_item(req);
if (!req.randomize() with { /* operation constraints */ })
`uvm_fatal(`gtn, "Randomization failed")
finish_item(req);
// CHK: display per checker_id associated with this operation
`uvm_info(`gtn, $sformatf("[PASS] <CHK_ID> — <op> completed addr=0x%0h data=0x%0h",
req.addr, req.data), UVM_MEDIUM)
endtask
endclass
7b — Base virtual sequence (skip if exists from S5)
Location: dv/sequences/<proj>/<proj>_base_vseq.sv
class <proj>_base_vseq extends uvm_sequence #(uvm_sequence_item);
`uvm_object_utils(<proj>_base_vseq)
`uvm_declare_p_sequencer(<proj>_virtual_seqr)
// RAL handle (populated by base_test before vseq starts)
<proj>_reg_block ral;
function new(string name = "<proj>_base_vseq");
super.new(name);
endfunction
// ── RAL helpers ─────────────────────────────────────────────────────────
task ral_write(uvm_reg rg, uvm_reg_data_t data, string chk_id = "");
uvm_status_e status;
rg.write(status, data, UVM_FRONTDOOR, .parent(this));
if (status != UVM_IS_OK)
`uvm_error(`gtn, $sformatf("[FAIL] RAL write to %s failed", rg.get_name()))
else if (chk_id != "")
`uvm_info(`gtn, $sformatf("[PASS] %s — RAL write %s=0x%0h",
chk_id, rg.get_name(), data), UVM_MEDIUM)
endtask
task ral_read(uvm_reg rg, output uvm_reg_data_t data, input string chk_id = "");
uvm_status_e status;
rg.read(status, data, UVM_FRONTDOOR, .parent(this));
if (status != UVM_IS_OK)
`uvm_error(`gtn, $sformatf("[FAIL] RAL read from %s failed", rg.get_name()))
endtask
task ral_check(uvm_reg rg, uvm_reg_data_t exp, string chk_id = "");
uvm_reg_data_t act;
ral_read(rg, act);
if (act !== exp)
`uvm_error(`gtn, $sformatf("[FAIL] %s — %s exp=0x%0h act=0x%0h",
chk_id, rg.get_name(), exp, act))
else
`uvm_info(`gtn, $sformatf("[PASS] %s — %s matches 0x%0h",
chk_id, rg.get_name(), exp), UVM_MEDIUM)
endtask
task ral_reset_walk();
// Walk all registers, check reset values match mirror
uvm_reg regs[$];
ral.get_registers(regs);
foreach (regs[i]) begin
uvm_reg_data_t reset_val = regs[i].get_reset();
ral_check(regs[i], reset_val,
$sformatf("CHK_%s_RESET", regs[i].get_name().toupper()));
end
endtask
// ── Timing helpers ───────────────────────────────────────────────────────
task wait_clocks(int n = 1);
// TODO: connect to clock via p_sequencer.cfg or vif
#(n * 10ns);
endtask
virtual task body();
// Override in derived vseqs
endtask
endclass
7c — Directed virtual sequence (one per testplan directed row)
Location: dv/sequences/<proj>/<test_name>_vseq.sv
// FILE: dv/sequences/<proj>/<test_name>_vseq.sv
// Feature : <feature>
// Sub-feature: <subfeature>
// Milestone : <milestone>
// Checker ID : <checker_id>
class <test_name>_vseq extends <proj>_base_vseq;
`uvm_object_utils(<test_name>_vseq)
function new(string name = "<test_name>_vseq");
super.new(name);
endfunction
task body();
// ── DUT config via RAL ─────────────────────────────────────────────
// TODO: set DUT operating mode / configuration registers
// <From testcase_description: DUT Config section>
// ── Stimulus ───────────────────────────────────────────────────────
// TODO: start agent sequences on p_sequencer.<agent>_seqr
// <From testcase_description: Stimulus section>
// Example: fork/join agent sequences as needed
// ── Expected Behavior / Checks ────────────────────────────────────
// TODO: poll for completion, check expected register state
// <From testcase_description: Checks + Pass Criteria sections>
// Checker display — embed CHK_ID in every check
// `uvm_info(`gtn, "[PASS] <checker_id> — <description>", UVM_MEDIUM)
endtask
endclass
Skeleton elaboration rules:
- Parse
testcase_description DUT Config section → generate RAL writes for named registers
- Parse Stimulus section → instantiate and start matching agent sequences
- Parse Expected Behavior / Checks → generate
ral_check() calls or scoreboard enable steps
- Parse Pass Criteria →
$display("[PASS] <checker_id> ...") or uvm_error on failure
- Leave as TODO where the description is ambiguous — flag with
// ⚠️ NEEDS_REVIEW
7d — Random virtual sequence
Location: dv/sequences/<proj>/<feature>_rand_vseq.sv
// Randomness sources: seq_item randomization + cfg randomization
class <feature>_rand_vseq extends <proj>_base_vseq;
`uvm_object_utils(<feature>_rand_vseq)
// Randomizable test parameters
rand int unsigned num_txns;
rand bit inject_error;
constraint c_defaults {
num_txns inside {[10:200]};
inject_error dist {0 := 90, 1 := 10};
}
function new(string name = "<feature>_rand_vseq");
super.new(name);
endfunction
task body();
repeat (num_txns) begin
// TODO: randomize and start protocol-specific sequence per involved agent
// Randomness flows from: this vseq constraints + seq_item constraints + cfg constraints
// Example:
// <proto>_write_seq wseq = <proto>_write_seq::type_id::create("wseq");
// wseq.randomize(); // seq_item randomized inside
// wseq.start(p_sequencer.<agent>_seqr);
// Coverage sampling is handled by VIP monitor → coverage.sv
// Checker ID display on scoreboard check (in scoreboard, not here)
end
endtask
endclass
7e — Test class (one per testplan row)
Location: dv/tests/<proj>_<test_name>_test.sv
// FILE: dv/tests/<proj>_<test_name>_test.sv
// Feature : <feature>
// Sub-feature: <subfeature>
// Milestone : <milestone>
// Checker(s) : <checker_id>
//
// Plusargs (runtime):
// +VERBOSE — set verbosity to UVM_HIGH
// +NUM_TXNS=<N> — override num_txns (random tests)
// +SEED=<N> — set explicit randomization seed
// +SB_DISABLE — disable scoreboard (debug)
// +<FEATURE>_EN=<0|1> — feature-specific enable
class <proj>_<test_name>_test extends <proj>_base_test;
`uvm_component_utils(<proj>_<test_name>_test)
function new(string name = "<proj>_<test_name>_test", uvm_component parent = null);
super.new(name, parent);
endfunction
// ── build_phase: apply test-specific cfg constraints ──────────────────
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Plusarg overrides
if ($test$plusargs("VERBOSE"))
cfg.uvm_verbosity = UVM_HIGH;
if ($test$plusargs("SB_DISABLE"))
cfg.sb_enable = 0;
begin
int num_txns_arg;
if ($value$plusargs("NUM_TXNS=%d", num_txns_arg))
cfg.num_txns = num_txns_arg; // override seq default
end
// Test-specific cfg randomization with additional constraints
// (base_cfg already randomized in base_test — apply post-randomize overrides)
// Example:
// cfg.sb_enable = 1; // force scoreboard on for this test
// cfg.agent_active[0] = UVM_ACTIVE; // ensure primary agent is active
// TODO: add <test_name>-specific constraints here
endfunction
// ── run_phase: create, randomize, start vseq ─────────────────────────
task run_phase(uvm_phase phase);
<test_name>_vseq vseq;
phase.raise_objection(this);
vseq = <test_name>_vseq::type_id::create("vseq");
vseq.ral = env.ral;
if (!vseq.randomize())
`uvm_fatal(`gtn, "vseq randomization failed")
vseq.start(env.virtual_seqr);
phase.drop_objection(this);
endtask
// ── report_phase: emit PASS/FAIL summary ──────────────────────────────
function void report_phase(uvm_phase phase);
uvm_report_server svr = uvm_report_server::get_server();
super.report_phase(phase);
if (svr.get_severity_count(UVM_ERROR) == 0 &&
svr.get_severity_count(UVM_FATAL) == 0)
`uvm_info(`gtn, $sformatf("[PASS] %s completed with no errors", get_type_name()), UVM_NONE)
else
`uvm_error(`gtn, $sformatf("[FAIL] %s completed with %0d error(s)",
get_type_name(), svr.get_severity_count(UVM_ERROR)))
endfunction
endclass
Step 8 — Checker ID Embedding Rules
Every generated file must embed Checker ID display messages at verification points:
| Location | Format |
|---|
| Sequence body — check passes | `uvm_info(`gtn, "[PASS] CHK_ID — description", UVM_MEDIUM) |
| Sequence body — check fails | `uvm_error(`gtn, "[FAIL] CHK_ID — description") |
| SVA — pass | $info("[PASS] CHK_ID at time %0t", $time); (in pass action block) |
| SVA — fail | $error("[FAIL] CHK_ID violated at time %0t", $time); |
| Monitor — protocol check | `uvm_info(`gtn, "[PASS] CHK_ID — protocol check", UVM_HIGH) |
| Illegal coverbin hit | `uvm_error(`gtn, "[FAIL] CHK_ID — illegal coverage bin hit") |
Rules:
- Every
checker_id from the testplan row must appear as a string literal in the generated file
- If
checker_type == "Assertion" and assertion_code is provided in testplan: embed the SVA in the vseq or test with a pass action block added
- If
checker_type == "Procedural": add ral_check() or scoreboard task stub with CHK_ID
- If
checker_type == "Both": embed both
Step 9 — Package Files
sequences_pkg.sv
Location: dv/sequences/<proj>_sequences_pkg.sv
package <proj>_sequences_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
// Import all VIP agent packages
import <vip1>_agent_pkg::*;
import <vip2>_agent_pkg::*;
// ...
// Agent sequences (per protocol)
`include "sequences/<PROTO1>/<proto1>_write_seq.sv"
`include "sequences/<PROTO1>/<proto1>_read_seq.sv"
// ... all generated agent sequence files
// Virtual sequences
`include "sequences/<proj>/<proj>_base_vseq.sv"
`include "sequences/<proj>/<proj>_reset_vseq.sv"
`include "sequences/<proj>/<testcase1>_vseq.sv"
// ... all generated vseq files
endpackage
tests_pkg.sv
Location: dv/tests/<proj>_tests_pkg.sv
package <proj>_tests_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
import <proj>_env_pkg::*;
import <proj>_sequences_pkg::*;
`include "tests/<proj>_base_test.sv"
`include "tests/<proj>_sanity_test.sv"
`include "tests/<proj>_<testcase1>_test.sv"
// ... all generated test files
endpackage
Step 10 — Update compile.f
Append to dv/compile.f (deduplicated):
// S6 sequences package
+incdir+${DV_ROOT}/sequences
${DV_ROOT}/sequences/<proj>_sequences_pkg.sv
// S6 tests package
+incdir+${DV_ROOT}/tests
${DV_ROOT}/tests/<proj>_tests_pkg.sv
Step 11 — Write dv_sequences_data.json
Write <PROJECT_ROOT>/dv/dv_sequences_data.json:
{
"skill": "dv-sequences",
"version": "1.0",
"project_name": "<name>",
"generated_date": "<ISO date>",
"sequences": [
{
"file": "dv/sequences/<proj>/<test_name>_vseq.sv",
"class": "<test_name>_vseq",
"type": "directed|random",
"feature": "...",
"milestone": "DV-I|DV-C|DV-F",
"checker_ids": ["CHK_..."]
}
],
"tests": [
{
"file": "dv/tests/<proj>_<test_name>_test.sv",
"class": "<proj>_<test_name>_test",
"vseq": "<test_name>_vseq",
"plusargs": ["+VERBOSE", "+NUM_TXNS=N", "+SB_DISABLE"],
"milestone": "DV-I|DV-C|DV-F"
}
],
"agent_sequences": [
{
"vip": "<vip_name>",
"protocol": "<proto>",
"files": ["dv/sequences/<PROTO>/<proto>_write_seq.sv", "..."]
}
],
"packages": {
"sequences_pkg": "dv/sequences/<proj>_sequences_pkg.sv",
"tests_pkg": "dv/tests/<proj>_tests_pkg.sv"
},
"summary": {
"total_tests": 0,
"directed": 0,
"random": 0,
"neg_stress": 0,
"dv_i": 0,
"dv_c": 0,
"dv_f": 0,
"todo_count": 0
}
}
Step 12 — Print Terminal Summary
============================================================
DV Sequences — Complete
Project : <PROJECT_NAME>
Output : <dv_root>
============================================================
Agent sequences: N files (N protocols)
Virtual sequences: N files
Test classes: N files
------------------------------------------------------------
Directed tests: N Random tests: N Neg/Stress: N
Milestone: DV-I=N DV-C=N DV-F=N
------------------------------------------------------------
⚠️ TODOs (NEEDS_REVIEW): N items
→ Run: grep -r "NEEDS_REVIEW" <dv_root>/sequences <dv_root>/tests
------------------------------------------------------------
Packages:
sequences_pkg: dv/sequences/<proj>_sequences_pkg.sv
tests_pkg: dv/tests/<proj>_tests_pkg.sv
------------------------------------------------------------
Next step: run /dv-assertions (S7) to generate SVA
or /dv-scoreboard (S8) to generate scoreboard
============================================================
Important Notes
- Never overwrite an existing file — always use safe_write (skip and warn)
- Every CHK_ID from the testplan must appear as a string literal in at least one generated file
- The
_rand_test suffix on random test names is mandatory (from S2 convention)
- Random vseqs must randomize both the vseq itself AND the seq_items inside
uvm_declare_p_sequencer must reference the exact virtual sequencer class from dv_tb_data.json
- All class names must use the project prefix from dv_tb_data.json
- If
assertion_code is non-empty in the testplan row, embed it verbatim in the vseq file with a pass-action $info("[PASS] <CHK_ID> ...") block added
Appendix — Generated File Layout
dv/
sequences/
<PROTOCOL1>/ ← agent sequences per VIP protocol
<proto1>_write_seq.sv
<proto1>_read_seq.sv
<proto1>_burst_seq.sv
<proto1>_error_seq.sv
<PROTOCOL2>/
...
<proj>/ ← virtual sequences (cross-agent, DUT-level)
<proj>_base_vseq.sv (skip if exists from S5)
<proj>_reset_vseq.sv (skip if exists from S5)
<tc1_name>_vseq.sv
<tc2_name>_vseq.sv
<feature>_rand_vseq.sv
...
<proj>_sequences_pkg.sv
tests/
<proj>_base_test.sv (skip if exists from S5)
<proj>_sanity_test.sv (skip if exists from S5)
<proj>_<tc1_name>_test.sv
<proj>_<tc2_name>_test.sv
...
<proj>_tests_pkg.sv