mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
@@ -120,6 +120,7 @@ Han Qi
|
||||
Harald Heckmann
|
||||
Hennadii Chernyshchyk
|
||||
hjsanjana
|
||||
Hongseok Choi
|
||||
Howard Su
|
||||
Huang Rui
|
||||
Huanghuang Zhou
|
||||
|
||||
+2
-1
@@ -5288,12 +5288,13 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
nodep->dotted(m_ds.m_dotText); // Maybe ""
|
||||
// Only flag FTaskRefs under generate-if/case blocks that may be
|
||||
// pruned. GenFor and plain begin-blocks won't be pruned by V3Param.
|
||||
// A generate-case block's parent is the GenCaseItem, not the GenCase.
|
||||
// VarXRef uses the broader m_genBlk flag (set for all GenBlocks)
|
||||
// because genfor unrolling also removes variables.
|
||||
if (m_ds.m_genBlk && m_ds.m_dotSymp) {
|
||||
const AstNode* const blkp = m_ds.m_dotSymp->nodep();
|
||||
if (VN_IS(blkp, GenBlock)
|
||||
&& (VN_IS(blkp->backp(), GenIf) || VN_IS(blkp->backp(), GenCase))) {
|
||||
&& (VN_IS(blkp->backp(), GenIf) || VN_IS(blkp->backp(), GenCaseItem))) {
|
||||
nodep->containsGenBlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-3
@@ -120,17 +120,22 @@ class LinkParseVisitor final : public VNVisitor {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
bool nestedIfBegin(AstGenBlock* nodep) { // Point at begin inside the GenIf
|
||||
bool nestedIfBegin(AstGenBlock* nodep) { // Point at begin inside the GenIf/GenCaseItem
|
||||
// IEEE says directly nested item is not a new block
|
||||
// The genblk name will get attached to the if true/false LOWER begin block(s)
|
||||
// 1: GENIF
|
||||
// -> 1:3: GENBLOCK [IMPLIED] // nodep passed to this function
|
||||
// 1:3:1: GENIF
|
||||
// 1:3:1:2: GENBLOCK genblk1 [IMPLIED]
|
||||
// Likewise for a generate case item holding only a generate if
|
||||
// 1: GENCASEITEM
|
||||
// -> 1:2: GENBLOCK [IMPLIED] // nodep passed to this function
|
||||
// 1:2:1: GENIF
|
||||
const AstNode* const backp = nodep->backp();
|
||||
return (nodep->implied() // User didn't provide begin/end
|
||||
&& VN_IS(backp, GenIf) && VN_CAST(backp, GenIf)->elsesp() == nodep
|
||||
&& !nodep->nextp() // No other statements under upper genif else
|
||||
&& ((VN_IS(backp, GenIf) && VN_CAST(backp, GenIf)->elsesp() == nodep)
|
||||
|| VN_IS(backp, GenCaseItem))
|
||||
&& !nodep->nextp() // No other statements under upper genif else/case item
|
||||
&& (VN_IS(nodep->itemsp(), GenIf)) // Begin has if underneath
|
||||
&& !nodep->itemsp()->nextp()); // Has only one item
|
||||
}
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,85 @@
|
||||
// DESCRIPTION: Verilator: Verify function calls through generate-case block references
|
||||
//
|
||||
// When a function is defined inside a generate-case item and called via a
|
||||
// dotted reference (e.g. blk.f()), the FUNCREF must survive generate
|
||||
// pruning. Previously the FUNCREF could point to a function in a pruned
|
||||
// case item, causing a broken-link internal error.
|
||||
//
|
||||
// A case item holding only a generate if is directly nested (IEEE 1800-2023
|
||||
// 27.5), so its blocks are named 'blk' in the module scope, not under a
|
||||
// 'genblk' scope.
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Hongseok Choi
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// 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
|
||||
|
||||
module sub #(
|
||||
parameter int P = 1
|
||||
) (
|
||||
output int o
|
||||
);
|
||||
// Referenced before the blocks are declared
|
||||
assign o = blk.f(P);
|
||||
|
||||
generate
|
||||
case (P)
|
||||
1, 2:
|
||||
if (P == 1) begin : blk
|
||||
int w = 1;
|
||||
function automatic int f(input int i);
|
||||
f = i + 10;
|
||||
endfunction
|
||||
end
|
||||
else begin : blk
|
||||
int w = 2;
|
||||
function automatic int f(input int i);
|
||||
f = i + 20;
|
||||
endfunction
|
||||
end
|
||||
4: begin : blk
|
||||
int w = 4;
|
||||
function automatic int f(input int i);
|
||||
f = i + 40;
|
||||
endfunction
|
||||
end
|
||||
default:
|
||||
begin : blk
|
||||
int w = 7;
|
||||
function automatic int f(input int i);
|
||||
f = i + 70;
|
||||
endfunction
|
||||
end
|
||||
endcase
|
||||
endgenerate
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
int o1;
|
||||
int o2;
|
||||
int o4;
|
||||
int o7;
|
||||
|
||||
sub #(.P(1)) u1 (.o(o1));
|
||||
sub #(.P(2)) u2 (.o(o2));
|
||||
sub #(.P(4)) u4 (.o(o4));
|
||||
sub #(.P(7)) u7 (.o(o7));
|
||||
|
||||
initial begin
|
||||
#1;
|
||||
`checkd(o1, 11);
|
||||
`checkd(o2, 22);
|
||||
`checkd(o4, 44);
|
||||
`checkd(o7, 77);
|
||||
`checkd(u1.blk.w, 1);
|
||||
`checkd(u2.blk.w, 2);
|
||||
`checkd(u4.blk.w, 4);
|
||||
`checkd(u7.blk.w, 7);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Reference in New Issue
Block a user