2026-04-23 10:50:23 +02:00
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 PlanV GmbH
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
`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
typedef enum bit [ 1 : 0 ] { TXN_READ , TXN_WRITE } txn_e ;
// Each constraint exercises one RHS shape allowed by IEEE 1800-2023 18.7.2
// (constraint_set on the right of the implication operator -> ). `mode`
// selects which constraint contributes; the others are vacuous.
class Forms ;
2026-04-23 18:47:22 +02:00
rand bit [ 3 : 0 ] mode ;
rand bit [ 3 : 0 ] a ;
rand bit [ 3 : 0 ] b ;
rand bit [ 3 : 0 ] c ;
2026-04-23 10:50:23 +02:00
rand bit [ 31 : 0 ] address ;
2026-04-23 18:47:22 +02:00
rand txn_e txn_type ;
rand bit [ 7 : 0 ] arr [ 4 ] ;
rand bit [ 3 : 0 ] uarr [ 3 ] ;
2026-04-23 10:50:23 +02:00
// Bare expression (legacy form, supported pre-PR via expr->expr).
constraint c_expr {
( mode = = 4 'd0 ) - > b = = 4 'h9 ;
}
// Brace-block: the exact shape from issue #7300.
constraint c_brace_repro {
( mode = = 4 'd1 ) - > {
if ( txn_type inside { TXN_READ } ) address % ( 1 < < 4 ) = = 0 ;
}
}
// Brace-block with multiple statements.
constraint c_brace_multi {
( mode = = 4 'd2 ) - > {
address [ 0 ] = = 1 'b0 ;
address [ 31 ] = = 1 'b0 ;
}
}
// Bare if (without surrounding braces).
constraint c_if {
( mode = = 4 'd3 ) - > if ( a = = 4 'h1 ) b = = 4 'h7 ;
}
// Bare if/else.
constraint c_if_else {
( mode = = 4 'd4 ) - > if ( a = = 4 'h1 ) b = = 4 'ha ;
else b = = 4 'hb ;
}
// Bare foreach.
constraint c_foreach {
( mode = = 4 'd5 ) - > foreach ( arr [ i ] ) arr [ i ] < 8 'h40 ;
}
// Bare unique (uses the static-array form V3Randomize supports today).
constraint c_unique {
( mode = = 4 'd6 ) - > unique { uarr } ;
}
// Bare soft.
constraint c_soft {
( mode = = 4 'd7 ) - > soft b = = 4 'hd ;
}
// Nested implication inside a brace block.
constraint c_nested {
( mode = = 4 'd8 ) - > {
( a = = 4 'h0 ) - > { b = = 4 'h5 ; }
}
}
endclass
// Conditional `disable soft` is meta-level: V3Randomize hoists it into a
// runtime AstIf attached to the setup task so the directive only fires
// when its outer condition is true. When override_flag==0, the soft
// `x == 4'h5` wins; when override_flag==1, the implication fires the
// disable AND the override `x == 4'hc`, so x must be 4'hc.
class DisSoft ;
bit override_flag ;
rand bit [ 3 : 0 ] x ;
constraint c_soft_x { soft x = = 4 'h5 ; }
constraint c_override {
( override_flag = = 1 'b1 ) - > disable soft x ;
( override_flag = = 1 'b1 ) - > x = = 4 'hc ;
}
endclass
// MemberSel target for `disable soft`. Cross-object reference (inner.y)
// parses as AstMemberSel; disable-soft must extract the variable name from
// that node shape too.
class Inner ;
rand bit [ 3 : 0 ] y ;
endclass
class DisSoftMember ;
bit override_flag ;
rand Inner inner ;
constraint c_soft_y { soft inner . y = = 4 'h5 ; }
constraint c_override {
( override_flag = = 1 'b1 ) - > disable soft inner . y ;
( override_flag = = 1 'b1 ) - > inner . y = = 4 'hc ;
}
function new ( ) ; inner = new ( ) ; endfunction
endclass
// `disable soft` in BOTH then and else arms of a single if. Exercises the
// hoist-list concat path in the else branch (a then-arm hoist already
// exists when the else-arm hoist is appended). We only check that the
// hard constraint in each arm fires correctly under its `pick` condition;
// soft enforcement priority is not asserted (Verilator's soft solver is
// best-effort). The condition variable `pick` is non-rand so the setup
// task sees its current value before the solver runs.
class DisSoftBothArms ;
bit [ 1 : 0 ] pick ;
rand bit [ 3 : 0 ] a ;
rand bit [ 3 : 0 ] b ;
constraint c_soft_a { soft a = = 4 'h7 ; }
constraint c_soft_b { soft b = = 4 'h8 ; }
constraint c_split {
if ( pick = = 2 'd0 ) { disable soft a ; a = = 4 'h1 ; }
else { disable soft b ; b = = 4 'h2 ; }
}
endclass
module t ;
2026-04-23 18:47:22 +02:00
Forms obj ;
2026-04-23 10:50:23 +02:00
DisSoft ds ;
2026-04-23 18:47:22 +02:00
int ok ;
2026-04-23 10:50:23 +02:00
initial begin
obj = new ( ) ;
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd0 ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . b , 4 'h9 ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd1 ; txn_type = = TXN_READ ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . address [ 3 : 0 ] , 4 'h0 ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd2 ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . address [ 0 ] , 1 'b0 ) ;
`checkh ( obj . address [ 31 ] , 1 'b0 ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd3 ; a = = 4 'h1 ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . b , 4 'h7 ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd4 ; a = = 4 'h1 ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . b , 4 'ha ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd4 ; a = = 4 'h2 ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . b , 4 'hb ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd5 ; } ;
`checkd ( ok , 1 ) ;
foreach ( obj . arr [ i ] ) `checkh ( obj . arr [ i ] < 8 'h40 , 1 'b1 ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd6 ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . uarr [ 0 ] = = obj . uarr [ 1 ] , 1 'b0 ) ;
`checkh ( obj . uarr [ 0 ] = = obj . uarr [ 2 ] , 1 'b0 ) ;
`checkh ( obj . uarr [ 1 ] = = obj . uarr [ 2 ] , 1 'b0 ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd7 ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . b , 4 'hd ) ;
end
repeat ( 10 ) begin
ok = obj . randomize ( ) with { mode = = 4 'd8 ; a = = 4 'h0 ; } ;
`checkd ( ok , 1 ) ;
`checkh ( obj . b , 4 'h5 ) ;
end
ds = new ( ) ;
ds . override_flag = 1 'b0 ;
repeat ( 10 ) begin
ok = ds . randomize ( ) ;
`checkd ( ok , 1 ) ;
`checkh ( ds . x , 4 'h5 ) ;
end
ds . override_flag = 1 'b1 ;
repeat ( 10 ) begin
ok = ds . randomize ( ) ;
`checkd ( ok , 1 ) ;
`checkh ( ds . x , 4 'hc ) ;
end
begin
automatic DisSoftMember dsm = new ( ) ;
dsm . override_flag = 1 'b0 ;
repeat ( 10 ) begin
ok = dsm . randomize ( ) ;
`checkd ( ok , 1 ) ;
`checkh ( dsm . inner . y , 4 'h5 ) ;
end
dsm . override_flag = 1 'b1 ;
repeat ( 10 ) begin
ok = dsm . randomize ( ) ;
`checkd ( ok , 1 ) ;
`checkh ( dsm . inner . y , 4 'hc ) ;
end
end
begin
automatic DisSoftBothArms dba = new ( ) ;
// pick==0: hard a==1 fires (then arm); hoisted disable_soft(a) runs
dba . pick = 2 'd0 ;
repeat ( 10 ) begin
ok = dba . randomize ( ) ;
`checkd ( ok , 1 ) ;
`checkh ( dba . a , 4 'h1 ) ;
end
// pick==1: hard b==2 fires (else arm); hoisted disable_soft(b) runs
dba . pick = 2 'd1 ;
repeat ( 10 ) begin
ok = dba . randomize ( ) ;
`checkd ( ok , 1 ) ;
`checkh ( dba . b , 4 'h2 ) ;
end
end
$write ( " *-* All Finished *-* \n " ) ;
$finish ;
end
endmodule