From c4dcdeab9a953913b6c16a58091c5fec3c76cf6c Mon Sep 17 00:00:00 2001 From: Pawel Kojma Date: Tue, 20 Jan 2026 13:14:11 +0100 Subject: [PATCH] Add parsing of solve-before inside foreach (#6934) --- src/V3Randomize.cpp | 16 ++++--- src/verilog.y | 6 +++ .../t/t_constraint_solve_before_unsup.out | 12 ++++++ .../t/t_constraint_solve_before_unsup.py | 16 +++++++ .../t/t_constraint_solve_before_unsup.v | 42 +++++++++++++++++++ 5 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 test_regress/t/t_constraint_solve_before_unsup.out create mode 100755 test_regress/t/t_constraint_solve_before_unsup.py create mode 100644 test_regress/t/t_constraint_solve_before_unsup.v diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 33de114b0..e34d15681 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -1309,8 +1309,9 @@ class ConstraintExprVisitor final : public VNVisitor { // Convert to plain foreach FileLine* const fl = nodep->fileline(); - AstNode* const arrayp = nodep->arrayp()->unlinkFrBack(); - if (m_wantSingle) { + if (!nodep->stmtsp()) { + nodep->unlinkFrBack(); + } else if (m_wantSingle) { AstNodeExpr* const itemp = editSingle(fl, nodep->stmtsp()); AstCStmt* const cstmtp = new AstCStmt{fl}; cstmtp->add("ret += \" \";\n"); @@ -1320,14 +1321,17 @@ class ConstraintExprVisitor final : public VNVisitor { AstCExpr* const cexprp = new AstCExpr{fl}; cexprp->dtypeSetString(); cexprp->add("([&]{\nstd::string ret;\n"); - cexprp->add(new AstBegin{fl, "", new AstForeach{fl, arrayp, cstmtp}, true}); + cexprp->add(new AstBegin{ + fl, "", new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), cstmtp}, true}); cexprp->add("return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";\n})()"); nodep->replaceWith(new AstSFormatF{fl, "%@", false, cexprp}); } else { iterateAndNextNull(nodep->stmtsp()); - nodep->replaceWith(new AstBegin{ - fl, "", new AstForeach{fl, arrayp, nodep->stmtsp()->unlinkFrBackWithNext()}, - true}); + nodep->replaceWith( + new AstBegin{fl, "", + new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), + nodep->stmtsp()->unlinkFrBackWithNext()}, + true}); } VL_DO_DANGLING(nodep->deleteTree(), nodep); } diff --git a/src/verilog.y b/src/verilog.y index 068086357..207b963a1 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -7846,7 +7846,13 @@ constraint_primary: // ==IEEE: constraint_primary constraint_expressionList: // ==IEEE: { constraint_expression } constraint_expression { $$ = $1; } + | ySOLVE solve_before_list yBEFORE solve_before_list ';' + { ($1)->v3warn(CONSTRAINTIGN, "Ignoring unsupported: solve-before only supported as top-level constraint statement"); + $$ = nullptr; DEL($2, $4); } | constraint_expressionList constraint_expression { $$ = addNextNull($1, $2); } + | constraint_expressionList ySOLVE solve_before_list yBEFORE solve_before_list ';' + { ($2)->v3warn(CONSTRAINTIGN, "Ignoring unsupported: solve-before only supported as top-level constraint statement"); + $$ = $1; DEL($3, $5); } ; constraint_expression: // ==IEEE: constraint_expression diff --git a/test_regress/t/t_constraint_solve_before_unsup.out b/test_regress/t/t_constraint_solve_before_unsup.out new file mode 100644 index 000000000..90519d765 --- /dev/null +++ b/test_regress/t/t_constraint_solve_before_unsup.out @@ -0,0 +1,12 @@ +%Warning-CONSTRAINTIGN: t/t_constraint_solve_before_unsup.v:20:7: Ignoring unsupported: solve-before only supported as top-level constraint statement + 20 | solve x before data[i]; + | ^~~~~ + ... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest + ... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message. +%Warning-CONSTRAINTIGN: t/t_constraint_solve_before_unsup.v:29:7: Ignoring unsupported: solve-before only supported as top-level constraint statement + 29 | solve x before cfg[i].w, cfg[i].r; + | ^~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_solve_before_unsup.v:30:7: Ignoring unsupported: solve-before only supported as top-level constraint statement + 30 | solve cfg[i].l before cfg[i].x; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_constraint_solve_before_unsup.py b/test_regress/t/t_constraint_solve_before_unsup.py new file mode 100755 index 000000000..6585af685 --- /dev/null +++ b/test_regress/t/t_constraint_solve_before_unsup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(fails=test.vlt_all, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_constraint_solve_before_unsup.v b/test_regress/t/t_constraint_solve_before_unsup.v new file mode 100644 index 000000000..6dfa584f1 --- /dev/null +++ b/test_regress/t/t_constraint_solve_before_unsup.v @@ -0,0 +1,42 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2026 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +typedef struct { + rand bit l; + rand bit x; + rand bit w; + rand bit r; +} reg_t; + +class Packet; + rand bit [7:0] data[5]; + rand bit x; + + constraint c_data { + foreach (data[i]) { + solve x before data[i]; + data[i] inside {8'h10, 8'h20, 8'h30, 8'h40, 8'h50}; + } + } + + rand reg_t cfg[]; + + constraint solves_only_c { + foreach (cfg[i]) { + solve x before cfg[i].w, cfg[i].r; + solve cfg[i].l before cfg[i].x; + } + } +endclass + +module t; + Packet p; + + initial begin + p = new; + void'(p.randomize()); + end +endmodule