280 lines
7.0 KiB
Systemverilog
280 lines
7.0 KiB
Systemverilog
// DESCRIPTION: Verilator: Verilog Test module
|
|
//
|
|
// This file ONLY is placed under the Creative Commons Public Domain.
|
|
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
|
// SPDX-License-Identifier: CC0-1.0
|
|
|
|
// Regression for: a random member of a rand unpacked struct that no constraint
|
|
// references must still be randomized (IEEE 1800-2023 18.4 - all random
|
|
// members of a rand unpacked struct are solved concurrently).
|
|
|
|
// 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)
|
|
`define checkgt(gotv,minv) do if (!((gotv) > (minv))) begin \
|
|
$write("%%Error: %s:%0d: got=%0d expected > %0d\n", `__FILE__, `__LINE__, (gotv), (minv)); `stop; end while(0)
|
|
// verilog_format: on
|
|
|
|
typedef struct {
|
|
rand bit [3:0] inner_id; // UNCONSTRAINED nested random member
|
|
} inner_t;
|
|
|
|
typedef struct {
|
|
rand bit [3:0] id; // UNCONSTRAINED random member
|
|
rand bit [2:0] size; // constrained random member
|
|
rand inner_t inner; // UNCONSTRAINED nested rand struct member
|
|
bit [3:0] fixed; // non-rand member: must keep its value
|
|
} unpacked_t;
|
|
|
|
typedef struct packed {
|
|
bit [3:0] id;
|
|
bit [2:0] size;
|
|
} packed_t;
|
|
|
|
class C;
|
|
rand unpacked_t u;
|
|
rand packed_t p;
|
|
// Reference ONLY .size on each; .id, .inner.inner_id are random members left
|
|
// unmentioned, and .fixed is a non-rand member.
|
|
constraint c {
|
|
u.size inside {[0 : 2]};
|
|
p.size inside {[0 : 2]};
|
|
}
|
|
function new();
|
|
u.fixed = 4'hA;
|
|
endfunction
|
|
endclass
|
|
|
|
// Shared struct type as a non-rand member of a different randomized class.
|
|
class D;
|
|
unpacked_t m;
|
|
rand bit [3:0] z;
|
|
constraint dz {z < 5;}
|
|
endclass
|
|
|
|
// Struct-in-struct: constraint reaches into the nested struct.
|
|
typedef struct {
|
|
rand bit [3:0] a; // constrained nested member
|
|
rand bit [3:0] b; // UNCONSTRAINED nested member
|
|
} inner2_t;
|
|
|
|
typedef struct {
|
|
rand inner2_t inr;
|
|
rand bit [3:0] x; // UNCONSTRAINED outer member
|
|
} outer_t;
|
|
|
|
class E;
|
|
rand outer_t o;
|
|
constraint eo {o.inr.a < 3;}
|
|
endclass
|
|
|
|
// A rand member with an initializer, and a randc member, both unreferenced.
|
|
typedef struct {
|
|
rand bit [3:0] wi = 4'h1; // rand member with initializer
|
|
randc bit [3:0] cyc; // randc member
|
|
rand bit [3:0] r; // constrained member
|
|
} extra_t;
|
|
|
|
class F;
|
|
rand extra_t s;
|
|
constraint fc {s.r < 5;}
|
|
endclass
|
|
|
|
// Unpacked array of struct as a rand member, left unreferenced by the constraint.
|
|
typedef struct {rand bit [3:0] f;} aelem_t;
|
|
|
|
typedef struct {
|
|
rand bit [3:0] g;
|
|
rand aelem_t es[2];
|
|
} arr_t;
|
|
|
|
class G;
|
|
rand arr_t o;
|
|
constraint gc {o.g < 5;}
|
|
endclass
|
|
|
|
// Rand members reached only through a NON-rand struct member: only the
|
|
// referenced leaf is solved.
|
|
typedef struct {
|
|
rand bit [3:0] kv; // unreferenced: must keep its value
|
|
rand bit [3:0] rv; // referenced
|
|
} under_t;
|
|
|
|
typedef struct {
|
|
under_t sub; // non-rand
|
|
rand bit [3:0] hv;
|
|
} hold_t;
|
|
|
|
class H;
|
|
rand hold_t o;
|
|
constraint hc {o.sub.rv < 5;}
|
|
function new();
|
|
o.sub.kv = 4'hC;
|
|
endfunction
|
|
endclass
|
|
|
|
// Same reached through dynamic arrays of structs.
|
|
typedef struct {
|
|
rand bit ec; // unreferenced: must keep its value
|
|
rand bit [7:0] ed; // referenced
|
|
} delem_t;
|
|
|
|
typedef struct {
|
|
delem_t subs[]; // non-rand
|
|
} douter_t;
|
|
|
|
class I;
|
|
rand douter_t cfgs[];
|
|
rand bit flip;
|
|
constraint ic {
|
|
foreach (cfgs[i]) {
|
|
cfgs[i].subs[0].ed[0] != flip;
|
|
}
|
|
}
|
|
function new();
|
|
cfgs = new[3];
|
|
foreach (cfgs[i]) begin
|
|
cfgs[i].subs = new[2];
|
|
for (int j = 0; j < 2; j++) cfgs[i].subs[j].ec = 1'b1;
|
|
end
|
|
endfunction
|
|
endclass
|
|
|
|
module t_constraint_struct_unref;
|
|
initial begin
|
|
C c;
|
|
D d;
|
|
E e;
|
|
F f;
|
|
G g;
|
|
H h;
|
|
I iarr;
|
|
int uid[16];
|
|
int pid[16];
|
|
int iid[16];
|
|
int zid[16];
|
|
int bid[16];
|
|
int xid[16];
|
|
int wid[16];
|
|
int cid[16];
|
|
int e0id[16];
|
|
int e1id[16];
|
|
int hid[16];
|
|
int un;
|
|
int pn;
|
|
int inn;
|
|
int zn;
|
|
int bn;
|
|
int xn;
|
|
int wn;
|
|
int cn;
|
|
int e0n;
|
|
int e1n;
|
|
int hn;
|
|
// Non-randomized use of the shared type: must stay untouched.
|
|
unpacked_t plain;
|
|
outer_t plain2;
|
|
c = new();
|
|
d = new();
|
|
e = new();
|
|
f = new();
|
|
g = new();
|
|
h = new();
|
|
iarr = new();
|
|
un = 0;
|
|
pn = 0;
|
|
inn = 0;
|
|
zn = 0;
|
|
bn = 0;
|
|
xn = 0;
|
|
wn = 0;
|
|
cn = 0;
|
|
e0n = 0;
|
|
e1n = 0;
|
|
hn = 0;
|
|
plain.id = 4'h5;
|
|
plain.size = 3'h6;
|
|
plain.inner.inner_id = 4'h7;
|
|
plain.fixed = 4'h8;
|
|
d.m.id = 4'h1;
|
|
d.m.size = 3'h2;
|
|
d.m.inner.inner_id = 4'h3;
|
|
d.m.fixed = 4'h4;
|
|
plain2.inr.a = 4'h9;
|
|
plain2.inr.b = 4'hA;
|
|
plain2.x = 4'hB;
|
|
for (int i = 0; i < 300; i++) begin
|
|
`checkd(c.randomize(), 1);
|
|
`checkd((c.u.size inside {[0 : 2]}), 1'b1);
|
|
`checkd((c.p.size inside {[0 : 2]}), 1'b1);
|
|
`checkd(c.u.fixed, 4'hA);
|
|
uid[c.u.id]++;
|
|
pid[c.p.id]++;
|
|
iid[c.u.inner.inner_id]++;
|
|
`checkd(d.randomize(), 1);
|
|
`checkd((d.z < 5), 1'b1);
|
|
`checkd(d.m.id, 4'h1);
|
|
`checkd(d.m.size, 3'h2);
|
|
`checkd(d.m.inner.inner_id, 4'h3);
|
|
`checkd(d.m.fixed, 4'h4);
|
|
zid[d.z]++;
|
|
`checkd(e.randomize(), 1);
|
|
`checkd((e.o.inr.a < 3), 1'b1);
|
|
bid[e.o.inr.b]++; // unreferenced nested member
|
|
xid[e.o.x]++; // unreferenced outer member
|
|
`checkd(f.randomize(), 1);
|
|
`checkd((f.s.r < 5), 1'b1);
|
|
wid[f.s.wi]++; // unreferenced rand member with initializer
|
|
cid[f.s.cyc]++; // unreferenced randc member
|
|
`checkd(g.randomize(), 1);
|
|
`checkd((g.o.g < 5), 1'b1);
|
|
e0id[g.o.es[0].f]++; // unreferenced array-of-struct element
|
|
e1id[g.o.es[1].f]++;
|
|
`checkd(h.randomize(), 1);
|
|
`checkd((h.o.sub.rv < 5), 1'b1);
|
|
`checkd(h.o.sub.kv, 4'hC);
|
|
hid[h.o.hv]++;
|
|
`checkd(iarr.randomize(), 1);
|
|
foreach (iarr.cfgs[k]) begin
|
|
`checkd((iarr.cfgs[k].subs[0].ed[0] != iarr.flip), 1'b1);
|
|
`checkd(iarr.cfgs[k].subs[0].ec, 1'b1);
|
|
`checkd(iarr.cfgs[k].subs[1].ec, 1'b1);
|
|
end
|
|
end
|
|
foreach (uid[k]) if (uid[k] > 0) un++;
|
|
foreach (pid[k]) if (pid[k] > 0) pn++;
|
|
foreach (iid[k]) if (iid[k] > 0) inn++;
|
|
foreach (zid[k]) if (zid[k] > 0) zn++;
|
|
foreach (bid[k]) if (bid[k] > 0) bn++;
|
|
foreach (xid[k]) if (xid[k] > 0) xn++;
|
|
foreach (wid[k]) if (wid[k] > 0) wn++;
|
|
foreach (cid[k]) if (cid[k] > 0) cn++;
|
|
foreach (e0id[k]) if (e0id[k] > 0) e0n++;
|
|
foreach (e1id[k]) if (e1id[k] > 0) e1n++;
|
|
foreach (hid[k]) if (hid[k] > 0) hn++;
|
|
// Unreferenced rand members must vary; packed struct is the control case.
|
|
`checkgt(un, 7);
|
|
`checkgt(pn, 7);
|
|
`checkgt(inn, 7);
|
|
`checkgt(zn, 3);
|
|
`checkgt(bn, 7);
|
|
`checkgt(xn, 7);
|
|
`checkgt(wn, 7);
|
|
`checkgt(cn, 7);
|
|
`checkgt(e0n, 7);
|
|
`checkgt(e1n, 7);
|
|
`checkgt(hn, 7);
|
|
`checkd(plain.id, 4'h5);
|
|
`checkd(plain.size, 3'h6);
|
|
`checkd(plain.inner.inner_id, 4'h7);
|
|
`checkd(plain.fixed, 4'h8);
|
|
`checkd(plain2.inr.a, 4'h9);
|
|
`checkd(plain2.inr.b, 4'hA);
|
|
`checkd(plain2.x, 4'hB);
|
|
|
|
$write("*-* All Finished *-*\n");
|
|
$finish;
|
|
end
|
|
endmodule
|