579 lines
14 KiB
Systemverilog
579 lines
14 KiB
Systemverilog
// DESCRIPTION: Verilator: Verilog Test module
|
|
//
|
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
|
// any use, without warranty, 2026 by Wilson Snyder.
|
|
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
|
// SPDX-License-Identifier: CC0-1.0
|
|
|
|
// Embedded covergroups whose coverage constructs reference members of the
|
|
// enclosing class. IEEE 1800-2023 19.4 allows class members in coverpoint
|
|
// expressions, conditional guards, option initialization, and other coverage
|
|
// constructs; IEEE 1800-2023 8.11 also allows 'this' within embedded covergroups.
|
|
|
|
// verilog_format: off
|
|
`define stop $stop
|
|
`define checkd(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__, `__LINE__, (gotv), (expv)); `stop; end while (0);
|
|
// verilog_format: on
|
|
|
|
bit [3:0] global_value;
|
|
|
|
covergroup GlobalCg;
|
|
cp_global: coverpoint global_value;
|
|
endgroup
|
|
|
|
class GlobalCgHolder;
|
|
GlobalCg cg;
|
|
|
|
function new();
|
|
cg = new;
|
|
endfunction
|
|
endclass
|
|
|
|
class Inner;
|
|
bit [3:0] value;
|
|
endclass
|
|
|
|
class Transaction;
|
|
bit [7:0] operand_a;
|
|
bit [1:0] operand_b;
|
|
Inner inner;
|
|
endclass
|
|
|
|
class Monitor;
|
|
bit [3:0] addr; // Direct member of the enclosing class
|
|
bit enable;
|
|
Transaction trx; // Class-handle member of the enclosing class
|
|
|
|
covergroup mon_cg;
|
|
cp_addr: coverpoint addr {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
cp_enabled: coverpoint addr iff (enable) {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
cp_op_a: coverpoint trx.operand_a {bins lo = {[0 : 127]}; bins hi = {[128 : 255]};}
|
|
cp_op_b: coverpoint trx.operand_b;
|
|
cp_inner: coverpoint trx.inner.value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
addr_x_op_b: cross cp_addr, cp_op_b;
|
|
endgroup
|
|
|
|
function new();
|
|
trx = new;
|
|
trx.inner = new;
|
|
mon_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] a, bit [7:0] oa, bit [1:0] ob, bit [3:0] iv);
|
|
addr = a;
|
|
enable = a[3];
|
|
trx.operand_a = oa;
|
|
trx.operand_b = ob;
|
|
trx.inner.value = iv;
|
|
mon_cg.sample();
|
|
endfunction
|
|
endclass
|
|
|
|
class BranchMonitor;
|
|
bit [2:0] value;
|
|
|
|
covergroup branch_cg;
|
|
cp_branch: coverpoint value {bins lo = {[0 : 3]}; bins hi = {[4 : 7]};}
|
|
endgroup
|
|
|
|
function new(bit choose_first);
|
|
if (choose_first) begin
|
|
branch_cg = new;
|
|
end
|
|
else begin
|
|
branch_cg = new;
|
|
end
|
|
endfunction
|
|
|
|
function void observe(bit [2:0] v);
|
|
value = v;
|
|
branch_cg.sample();
|
|
endfunction
|
|
endclass
|
|
|
|
// IEEE 1800-2012 8.13 makes inherited members part of the derived class as if declared
|
|
// there; 19.4 permits those class members in an embedded covergroup.
|
|
class BaseMonitor;
|
|
protected bit [3:0] inherited_value;
|
|
|
|
covergroup base_cg;
|
|
cp_base: coverpoint inherited_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
function new();
|
|
base_cg = new;
|
|
endfunction
|
|
endclass
|
|
|
|
class DerivedMonitor extends BaseMonitor;
|
|
bit [3:0] derived_value;
|
|
|
|
covergroup derived_cg;
|
|
cp_inherited: coverpoint inherited_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
cp_this_inherited: coverpoint this.inherited_value {
|
|
bins lo = {[0 : 7]};
|
|
bins hi = {[8 : 15]};
|
|
}
|
|
cp_derived: coverpoint derived_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
cp_cross: cross cp_inherited, cp_derived;
|
|
endgroup
|
|
|
|
function new();
|
|
derived_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
inherited_value = v;
|
|
derived_value = 15 - v;
|
|
base_cg.sample();
|
|
derived_cg.sample();
|
|
endfunction
|
|
endclass
|
|
|
|
// IEEE 1800-2012 8.18 makes protected members visible to subclasses. Combined with
|
|
// 8.13 and 19.4, a leaf class covergroup may cover a protected root-class property.
|
|
class RootMonitor;
|
|
protected bit [3:0] root_value;
|
|
endclass
|
|
|
|
class MiddleMonitor extends RootMonitor;
|
|
endclass
|
|
|
|
class LeafMonitor extends MiddleMonitor;
|
|
bit [3:0] leaf_value;
|
|
|
|
covergroup leaf_cg;
|
|
cp_root: coverpoint root_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
cp_leaf: coverpoint leaf_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
cp_cross: cross cp_root, cp_leaf;
|
|
endgroup
|
|
|
|
function new();
|
|
leaf_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
root_value = v;
|
|
leaf_value = 15 - v;
|
|
leaf_cg.sample();
|
|
endfunction
|
|
endclass
|
|
|
|
class ParameterizedBaseMonitor #(
|
|
int WIDTH = 4
|
|
);
|
|
bit [WIDTH-1:0] parameterized_value;
|
|
endclass
|
|
|
|
class ParameterizedDerivedMonitor extends ParameterizedBaseMonitor #(4);
|
|
covergroup parameterized_cg;
|
|
cp_parameterized: coverpoint parameterized_value {
|
|
bins lo = {[0 : 7]};
|
|
bins hi = {[8 : 15]};
|
|
}
|
|
endgroup
|
|
|
|
function new();
|
|
parameterized_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
parameterized_value = v;
|
|
parameterized_cg.sample();
|
|
endfunction
|
|
endclass
|
|
|
|
class ThisMonitor;
|
|
bit [3:0] current;
|
|
|
|
covergroup this_cg with function sample(bit [3:0] sampled_current);
|
|
cp_this: coverpoint current iff (sampled_current == current) {
|
|
bins lo = {[0 : 7]};
|
|
bins hi = {[8 : 15]};
|
|
}
|
|
endgroup
|
|
|
|
function new();
|
|
this_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
current = v;
|
|
this_cg.sample(this.current);
|
|
endfunction
|
|
endclass
|
|
|
|
class ThisSampleMonitor;
|
|
bit [3:0] sampled_value;
|
|
localparam bit [3:0] local_value = 4'ha;
|
|
|
|
covergroup this_sample_cg with function sample(bit [3:0] sampled_value);
|
|
cp_this_member: coverpoint this.sampled_value {
|
|
bins lo = {[0 : 7]};
|
|
bins hi = {[8 : 15]};
|
|
}
|
|
cp_this_parameter: coverpoint this.local_value;
|
|
cp_this_sample: coverpoint sampled_value iff (sampled_value == this.sampled_value) {
|
|
bins lo = {[0 : 7]};
|
|
bins hi = {[8 : 15]};
|
|
}
|
|
endgroup
|
|
|
|
function new();
|
|
this_sample_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
this.sampled_value = v;
|
|
this_sample_cg.sample(this.sampled_value);
|
|
endfunction
|
|
endclass
|
|
|
|
`ifdef VERILATOR
|
|
// IEEE 1800-2012 8.11 explicitly permits 'this' in covergroups embedded within classes.
|
|
class ThisHandleMonitor;
|
|
bit [3:0] current;
|
|
|
|
covergroup this_handle_cg;
|
|
cp_this_handle: coverpoint current iff (this == this) {
|
|
bins lo = {[0 : 7]};
|
|
bins hi = {[8 : 15]};
|
|
}
|
|
endgroup
|
|
|
|
function new();
|
|
this_handle_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
current = v;
|
|
this_handle_cg.sample();
|
|
endfunction
|
|
endclass
|
|
`endif
|
|
|
|
class ClockEvent;
|
|
bit clk;
|
|
endclass
|
|
|
|
class ClockMonitor;
|
|
ClockEvent ev;
|
|
bit [3:0] sampled;
|
|
|
|
covergroup clock_cg @(posedge ev.clk);
|
|
cp_clocked: coverpoint sampled {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
function new();
|
|
ev = new;
|
|
ev.clk = 0;
|
|
clock_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
sampled = v;
|
|
ev.clk = 0;
|
|
ev.clk = 1;
|
|
endfunction
|
|
endclass
|
|
|
|
class VectorClockMonitor;
|
|
bit [2:0] clk_vec;
|
|
bit [3:0] sampled;
|
|
|
|
covergroup pos_cg @(posedge clk_vec);
|
|
cp_pos: coverpoint sampled {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
covergroup neg_cg @(negedge clk_vec);
|
|
cp_neg: coverpoint sampled {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
covergroup both_cg @(posedge clk_vec or negedge clk_vec);
|
|
cp_both: coverpoint sampled {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
covergroup edge_cg @(edge clk_vec);
|
|
cp_edge: coverpoint sampled {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
covergroup change_cg @(clk_vec);
|
|
cp_change: coverpoint sampled {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
function new();
|
|
clk_vec = 3'b000;
|
|
pos_cg = new;
|
|
neg_cg = new;
|
|
both_cg = new;
|
|
edge_cg = new;
|
|
change_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [2:0] next_clk, bit [3:0] value);
|
|
sampled = value;
|
|
clk_vec = next_clk;
|
|
endfunction
|
|
|
|
function void observe_bit(bit next_clk, bit [3:0] value);
|
|
sampled = value;
|
|
clk_vec[0] = next_clk;
|
|
endfunction
|
|
endclass
|
|
|
|
class CopyMonitor;
|
|
bit [3:0] value;
|
|
|
|
covergroup copy_cg;
|
|
cp_copy: coverpoint value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
function new();
|
|
copy_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
value = v;
|
|
copy_cg.sample();
|
|
endfunction
|
|
endclass
|
|
|
|
class CloneBaseMonitor;
|
|
bit [3:0] base_value;
|
|
|
|
covergroup cg;
|
|
cp_base: coverpoint base_value;
|
|
endgroup
|
|
|
|
function new();
|
|
cg = new;
|
|
endfunction
|
|
endclass
|
|
|
|
class CloneDerivedMonitor extends CloneBaseMonitor;
|
|
bit [3:0] derived_value;
|
|
|
|
covergroup cg;
|
|
cp_derived: coverpoint derived_value;
|
|
endgroup
|
|
|
|
function new();
|
|
cg = new;
|
|
endfunction
|
|
endclass
|
|
|
|
class StaticMonitor;
|
|
static bit [3:0] static_value;
|
|
bit [3:0] instance_value;
|
|
|
|
covergroup static_cg;
|
|
cp_static: coverpoint static_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
cp_instance: coverpoint instance_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
function new();
|
|
static_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
static_value = v;
|
|
instance_value = v;
|
|
static_cg.sample();
|
|
endfunction
|
|
endclass
|
|
|
|
class StaticOnlyMonitor;
|
|
static bit [3:0] static_value;
|
|
|
|
covergroup static_only_cg with function sample(bit [3:0] sampled_value);
|
|
cp_static_only: coverpoint static_value iff (sampled_value == static_value) {
|
|
bins lo = {[0 : 7]};
|
|
bins hi = {[8 : 15]};
|
|
}
|
|
endgroup
|
|
|
|
function new();
|
|
static_only_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
static_value = v;
|
|
static_only_cg.sample(this.static_value);
|
|
endfunction
|
|
endclass
|
|
|
|
class MultipleMonitor;
|
|
bit [3:0] first_value;
|
|
bit [3:0] second_value;
|
|
|
|
covergroup first_cg;
|
|
cp_first: coverpoint first_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
covergroup second_cg;
|
|
cp_second: coverpoint second_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
function new();
|
|
first_cg = new;
|
|
second_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] first, bit [3:0] second);
|
|
first_value = first;
|
|
second_value = second;
|
|
first_cg.sample();
|
|
second_cg.sample();
|
|
endfunction
|
|
endclass
|
|
|
|
class NestedContainer;
|
|
protected static bit [3:0] static_value;
|
|
bit [3:0] value;
|
|
|
|
class NestedMonitor;
|
|
bit [3:0] local_value;
|
|
NestedContainer container;
|
|
|
|
covergroup nested_cg;
|
|
cp_local: coverpoint local_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
cp_container: coverpoint container.value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
// IEEE 1800-2012 8.23 permits implicit access to static outer-class members.
|
|
cp_static: coverpoint static_value {bins lo = {[0 : 7]}; bins hi = {[8 : 15]};}
|
|
endgroup
|
|
|
|
function new(NestedContainer container_arg);
|
|
container = container_arg;
|
|
nested_cg = new;
|
|
endfunction
|
|
|
|
function void observe(bit [3:0] v);
|
|
local_value = v;
|
|
container.value = 15 - v;
|
|
static_value = v;
|
|
nested_cg.sample();
|
|
endfunction
|
|
endclass
|
|
endclass
|
|
|
|
class UnconstructedMonitor;
|
|
bit [3:0] local_value;
|
|
|
|
covergroup unconstructed_cg;
|
|
cp: coverpoint local_value;
|
|
cp2: coverpoint local_value[2:0];
|
|
cp_x_cp2: cross cp, cp2;
|
|
endgroup
|
|
|
|
function new();
|
|
endfunction
|
|
endclass
|
|
|
|
module t;
|
|
Monitor mon;
|
|
BranchMonitor branch_a;
|
|
BranchMonitor branch_b;
|
|
DerivedMonitor derived;
|
|
LeafMonitor leaf;
|
|
ParameterizedDerivedMonitor parameterized;
|
|
ThisMonitor this_mon;
|
|
ThisSampleMonitor this_sample_mon;
|
|
`ifdef VERILATOR
|
|
ThisHandleMonitor this_handle_mon;
|
|
`endif
|
|
ClockMonitor clock_mon;
|
|
VectorClockMonitor vector_clock_mon;
|
|
CopyMonitor copy_src;
|
|
CopyMonitor copy_dst;
|
|
GlobalCgHolder global_src;
|
|
GlobalCgHolder global_dst;
|
|
CloneDerivedMonitor clone_src;
|
|
CloneDerivedMonitor clone_dst;
|
|
CloneBaseMonitor clone_base_view;
|
|
StaticMonitor static_mon;
|
|
StaticOnlyMonitor static_only_mon;
|
|
MultipleMonitor multiple_mon;
|
|
NestedContainer nested_container;
|
|
NestedContainer::NestedMonitor nested_mon;
|
|
UnconstructedMonitor unconstructed_mon;
|
|
int i;
|
|
|
|
initial begin
|
|
mon = new;
|
|
branch_a = new(1);
|
|
branch_b = new(0);
|
|
derived = new;
|
|
leaf = new;
|
|
parameterized = new;
|
|
this_mon = new;
|
|
this_sample_mon = new;
|
|
`ifdef VERILATOR
|
|
this_handle_mon = new;
|
|
`endif
|
|
clock_mon = new;
|
|
vector_clock_mon = new;
|
|
copy_src = new;
|
|
global_src = new;
|
|
clone_src = new;
|
|
static_mon = new;
|
|
static_only_mon = new;
|
|
multiple_mon = new;
|
|
nested_container = new;
|
|
nested_mon = new(nested_container);
|
|
unconstructed_mon = new;
|
|
`checkd(unconstructed_mon.unconstructed_cg == null, 1);
|
|
|
|
for (i = 0; i < 16; ++i) begin
|
|
mon.observe(i[3:0], i[7:0] * 17, i[1:0], i[3:0]);
|
|
derived.observe(i[3:0]);
|
|
leaf.observe(i[3:0]);
|
|
parameterized.observe(i[3:0]);
|
|
this_mon.observe(i[3:0]);
|
|
this_sample_mon.observe(i[3:0]);
|
|
`ifdef VERILATOR
|
|
this_handle_mon.observe(i[3:0]);
|
|
`endif
|
|
clock_mon.observe(i[3:0]);
|
|
static_mon.observe(i[3:0]);
|
|
static_only_mon.observe(i[3:0]);
|
|
multiple_mon.observe(i[3:0], 15 - i[3:0]);
|
|
nested_mon.observe(i[3:0]);
|
|
end
|
|
|
|
vector_clock_mon.observe(3'b010, 4'hf);
|
|
vector_clock_mon.observe(3'b011, 4'h1);
|
|
vector_clock_mon.observe(3'b010, 4'h2);
|
|
vector_clock_mon.observe(3'b000, 4'he);
|
|
vector_clock_mon.observe_bit(1'b1, 4'h3);
|
|
vector_clock_mon.observe_bit(1'b0, 4'h4);
|
|
|
|
for (i = 0; i < 8; ++i) begin
|
|
branch_a.observe(i[2:0]);
|
|
branch_b.observe(i[2:0]);
|
|
end
|
|
|
|
copy_src.observe(4'h1);
|
|
`ifdef VERILATOR
|
|
// IEEE 1800-2023 8.12 requires embedded covergroups to be null after a shallow copy.
|
|
// No new coverage object is created, so the copied object's properties are not covered.
|
|
// Questa instead aliases the source coverage object; Xcelium retains a non-null handle
|
|
// whose source and copied instances both report zero coverage.
|
|
copy_dst = new copy_src;
|
|
`checkd(copy_dst.copy_cg == null, 1);
|
|
clone_dst = new clone_src;
|
|
clone_base_view = clone_dst;
|
|
`checkd(clone_dst.cg == null, 1);
|
|
`checkd(clone_base_view.cg == null, 1);
|
|
`endif
|
|
|
|
global_dst = new global_src;
|
|
`ifndef NC
|
|
// Comparing a covergroup variable with a non-null value is unsupported in Xcelium.
|
|
`checkd(global_dst.cg == global_src.cg, 1);
|
|
`endif
|
|
|
|
$write("*-* All Finished *-*\n");
|
|
$finish;
|
|
end
|
|
endmodule
|