$test$plusargs answers one question: was +NAME given on the command line. It returns 1 or 0.
$value$plusargs goes further: it matches the prefix, parses the rest through a format string into a variable, and returns nonzero on a match. Existence flags switch features on. Value plusargs carry numbers, strings and hex values into the run.
Format | Parses | Into |
|---|---|---|
| Decimal integer |
|
| Hexadecimal | Any vector or integer |
| Octal | Any vector or integer |
| Binary | Any vector or integer |
| Word string |
|
| Real |
|
Give every knob its default at the declaration. A successful parse overwrites it, so absence leaves a sane value behind.
// snippet
if (!$value$plusargs("NUM_TXNS=%d", num_txns))
$display("NUM_TXNS not given, keeping default %0d", num_txns);Treat the return as a match report, not a validity proof. A malformed value can return nonzero while the variable stays untouched on some tools, so check ranges after parsing.
Mandatory knobs test the return and stop without the value. Optional knobs ignore the return and keep the default.
It returns 0 and the variable keeps its old value. That is why defaults live in the declaration: absence leaves them intact.
$test$plusargs matches prefixes, not whole names. +ENABLE_COVERAGE_X also satisfies a check for ENABLE_COVERAGE, so keep knob names apart.
Type hex values without underscores, as in +BASE_ADDR=20000000. Some tools reject the underscore form during %h parsing.
A family of numbered plusargs accepts a variable-length list. The loop stops at the first missing index.
// snippet
// Accept +ERR_ADDR0=... +ERR_ADDR1=... up to 8 injection points
bit [31:0] err_addr[$];
initial begin
bit [31:0] val;
string key;
for (int i = 0; i < 8; i++) begin
key = $sformatf("ERR_ADDR%0d=%%h", i);
if (!$value$plusargs(key, val)) break;
err_addr.push_back(val);
end
endProduction testbenches parse once into one registry and print it. The registry below is a class with no top module, so it is not run in this course's checks.
// not-run: class-only listing with no top module to run (Verilator 5.048 compiles it)
class knob_registry;
int num_txns = 100;
int verbosity = 1;
string test_name = "smoke";
bit enable_cov = 0;
function void parse();
void'($value$plusargs("NUM_TXNS=%d", num_txns));
void'($value$plusargs("VERBOSITY=%d", verbosity));
void'($value$plusargs("TESTNAME=%s", test_name));
enable_cov = $test$plusargs("ENABLE_COVERAGE");
print();
endfunction
function void print();
$display("=== KNOBS ===========================");
$display(" TESTNAME = %s", test_name);
$display(" NUM_TXNS = %0d", num_txns);
$display(" VERBOSITY = %0d", verbosity);
$display(" ENABLE_COVERAGE = %0b", enable_cov);
$display("=====================================");
endfunction
endclassThe format must match how the value is typed. %d stops at hex digits past 9, so the parse fails or truncates. Use %h for hex values.
Two things: it pays parse overhead per transaction, and it scatters configuration across components. Parse once at time zero into a registry and hand the value down.
Each component runs with its own default, so the testbench disagrees with itself. One registry with one default per knob removes the drift.
Four knobs are parsed once with no plusargs on the command line. Every return reads 0 and every default survives, which the checks confirm.
module tb_plusargs;
integer num_txns = 100; // default: small smoke count
integer verbosity = 1; // default: normal logging
reg [31:0] base_addr = 32'h10000000; // default base
reg enable_cov = 0; // default: coverage off
integer errors = 0;
integer matched;
initial begin
// Each knob is parsed at most once, at time zero.
// With no plusargs given, every call returns 0.
matched = $value$plusargs("NUM_TXNS=%d", num_txns);
if (matched != 0) errors++;
matched = $value$plusargs("VERBOSITY=%d", verbosity);
if (matched != 0) errors++;
matched = $value$plusargs("BASE_ADDR=%h", base_addr);
if (matched != 0) errors++;
if ($test$plusargs("ENABLE_COVERAGE") != 0) errors++;
// Defaults survive untouched.
if (num_txns != 100) errors++;
if (verbosity != 1) errors++;
if (base_addr != 32'h10000000) errors++;
if (enable_cov != 0) errors++;
if (errors == 0) $display("PASS: 4 knobs held defaults with no plusargs given");
else $fatal(1, "FAIL: %0d default checks did not hold", errors);
$finish;
end
endmodule