Support dotted access to ports of a direct hier_block instance. (#6595)

Accessing the ports of hier_block instances directly under the current
hier_block (or top level) work just fine (the heir stub .sv has them),
and this can simplify hooking up dotted references into hier blocks:
push part of the reference under the hier block into the hier block, and
wire it to a port, then resolve the rest of the reference to the port of
the instance.
This commit is contained in:
Geza Lore 2025-10-25 19:39:21 +02:00 committed by GitHub
parent 68b227065e
commit 0ead54b17e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 81 additions and 11 deletions

View File

@ -143,8 +143,11 @@ Limitations
Hierarchy blocks have some limitations, including: Hierarchy blocks have some limitations, including:
* The hierarchy block cannot be accessed using dot (.) from the upper * Internals of the hierarchy block cannot be accessed using dot (.) from
module(s) or other hierarchy blocks. the upper module(s) or other hierarchy blocks, except that ports of a
hierarchy block instance can be accessed from the directly enclosing
nested hierarchy block, or from the top level non-hierarchical portions
of the design if not a nested hierarchy block.
* Modport cannot be used at the hierarchical block boundary. * Modport cannot be used at the hierarchical block boundary.

View File

@ -729,8 +729,8 @@ public:
if (lookupSymp) { if (lookupSymp) {
if (const AstCell* const cellp = VN_CAST(lookupSymp->nodep(), Cell)) { if (const AstCell* const cellp = VN_CAST(lookupSymp->nodep(), Cell)) {
if (const AstNodeModule* const modp = cellp->modp()) { if (const AstNodeModule* const modp = cellp->modp()) {
if (modp->hierBlock()) { if (modp->hierBlock() && !leftname.empty()) {
refLocationp->v3error("Cannot access inside hierarchical block"); refLocationp->v3error("Cannot access scope inside hierarchical block");
} else if (VN_IS(modp, NotFoundModule)) { } else if (VN_IS(modp, NotFoundModule)) {
refLocationp->v3error("Dotted reference to instance that refers to " refLocationp->v3error("Dotted reference to instance that refers to "
"missing module/interface: " "missing module/interface: "
@ -3004,6 +3004,22 @@ class LinkDotResolveVisitor final : public VNVisitor {
} }
} }
// Returns true and issues error iff 'varp' cannot be accesed with a VarXRef
// in a hier_block given by 'scopeSymp'
bool errorHierNonPort(AstVarXRef* refp, AstVar* varp, VSymEnt* scopeSymp) {
// OK to access ports on hier_block
if (varp->isIO()) return false;
// OK if not an instance
const AstCell* const cellp = VN_CAST(scopeSymp->nodep(), Cell);
if (!cellp) return false;
// Ok if not a hier_block
const AstNodeModule* const modp = cellp->modp();
if (!modp->hierBlock()) return false;
// Bad
refp->v3error("Cannot access non-port symbols inside hierarchical block");
return true;
}
#define LINKDOT_VISIT_START() \ #define LINKDOT_VISIT_START() \
VL_RESTORER(m_indent); \ VL_RESTORER(m_indent); \
++m_indent; ++m_indent;
@ -4104,6 +4120,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
nodep->varp(varp); nodep->varp(varp);
updateVarUse(nodep->varp()); updateVarUse(nodep->varp());
UINFO(7, indent() << "Resolved " << nodep); // Also prints varp UINFO(7, indent() << "Resolved " << nodep); // Also prints varp
// If found, check if it's ok to access in case it's in a hier_block
if (nodep->varp() && errorHierNonPort(nodep, nodep->varp(), dotSymp)) return;
if (!nodep->varp()) { if (!nodep->varp()) {
nodep->v3error("Can't find definition of " nodep->v3error("Can't find definition of "
<< AstNode::prettyNameQ(baddot) << " in dotted signal: '" << AstNode::prettyNameQ(baddot) << " in dotted signal: '"
@ -4130,6 +4148,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
VSymEnt* const foundp VSymEnt* const foundp
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, true); = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, true);
AstVarScope* vscp = foundp ? VN_AS(foundp->nodep(), VarScope) : nullptr; AstVarScope* vscp = foundp ? VN_AS(foundp->nodep(), VarScope) : nullptr;
// If found, check if it's ok to access in case it's in a hier_block
if (vscp && errorHierNonPort(nodep, vscp->varp(), dotSymp)) return;
if (!vscp) { if (!vscp) {
nodep->v3error("Can't find varpin scope of " nodep->v3error("Can't find varpin scope of "
<< AstNode::prettyNameQ(baddot) << " in dotted signal: '" << AstNode::prettyNameQ(baddot) << " in dotted signal: '"

View File

@ -55,7 +55,9 @@ module t (/*AUTOARG*/
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (out3 != out3_2) $stop; if (out3 != out3_2) $stop;
$display("%d out0:%d %d %d %d %d", count, out0, out1, out2, out3, out5, out6); $display("%d %m out0:%d %d %d %d %d", count, out0, out1, out2, out3, out5, out6);
$display("%d %m child input ports: %d %d %d", count, i_sub1.in, i_sub2.in, i_sub3.in);
$display("%d %m child output ports: %d %d %d", count, i_sub1.out, i_sub2.out, i_sub3.out);
if (count == 16) begin if (count == 16) begin
if (out6 == 19) begin if (out6 == 19) begin
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
@ -192,8 +194,16 @@ module sub3 #(
assign out = out4; assign out = out4;
/* verilator lint_off REALCVT */ /* verilator lint_off REALCVT */
sub4 #(.P0(1.6), .P1(3.1), .P3(4.1)) i_sub4_0(.clk(clk), .in(ff), .out(out4)); // incr 2 sub4 #(.P0(1.6), .P1(3.1), .P3(4.1)) i_sub4_0(.clk(clk), .in(ff), .out(out4)); // incr 2
sub4 #(.P0(2.4), .P1(3.1), .P3(5)) i_sub4_1(.clk(clk), .in(ff), .out(out4_2)); sub4 #(.P0(2.4), .P1(3.1), .P3(5)) i_sub4_1(.clk(clk), .in(), .out(out4_2));
/* verilator lint_on REALCVT */ /* verilator lint_on REALCVT */
/* verilator lint_off ASSIGNIN */
assign i_sub4_1.in = ff; // Hierarchical reference to port of hier_block is OK
/* verilator lint_off ASSIGNIN */
always @(posedge clk) begin
$display("%d %m child input ports: %d %d", $time, i_sub4_0.in, i_sub4_1.in);
$display("%d %m child output ports: %d %d", $time, i_sub4_0.out, i_sub4_1.out);
end
endmodule endmodule
module sub4 #( module sub4 #(
@ -248,6 +258,10 @@ module sub4 #(
$display("in[%d][%d] act:%d exp:%d", i, j, sub5_out[i][j], exp); $display("in[%d][%d] act:%d exp:%d", i, j, sub5_out[i][j], exp);
$stop; $stop;
end end
if (i_sub5.out[i][j] != exp) begin
$display("in[%d][%d] act:%d exp:%d", i, j, i_sub5.out[i][j], exp);
$stop;
end
end end
end end
end end

View File

@ -3,7 +3,15 @@
21 | sub0 #(UNPACKED) i_sub0(.clk(clk), .in(8'(count)), .out(out0)); 21 | sub0 #(UNPACKED) i_sub0(.clk(clk), .in(8'(count)), .out(out0));
| ^~~~~~~~ | ^~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_hier_block0_bad.v:26:42: Cannot access inside hierarchical block %Error: t/t_hier_block0_bad.v:62:41: Cannot access non-port symbols inside hierarchical block
26 | $display("%d %d %d", count, i_sub0.ff, out1); : ... note: In instance 't.i_sub0'
62 | $display("%m: i_sub.x: %d", i_sub.x);
| ^
%Error: t/t_hier_block0_bad.v:26:50: Cannot access non-port symbols inside hierarchical block
: ... note: In instance 't'
26 | $display("%d i_sub0.ff: %d", count, i_sub0.ff);
| ^~ | ^~
%Error: t/t_hier_block0_bad.v:27:63: Cannot access scope inside hierarchical block
27 | $display("%d i_sub0.i_sub.out: %d", count, i_sub0.i_sub.out);
| ^~~
%Error: Exiting due to %Error: Exiting due to

View File

@ -22,8 +22,12 @@ module t (/*AUTOARG*/
sub1 #(.T(logic[7:0])) i_sub1(.in(out0), .out(out1)); sub1 #(.T(logic[7:0])) i_sub1(.in(out0), .out(out1));
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
// dotted access under hierarchical block is not allowed // dotted access under hierarchical block is not allowed ...
$display("%d %d %d", count, i_sub0.ff, out1); $display("%d i_sub0.ff: %d", count, i_sub0.ff);
$display("%d i_sub0.i_sub.out: %d", count, i_sub0.i_sub.out);
// ... Except for ports on a dierct hierarchical child
$display("%d i_sub0.out: %d", count, i_sub0.out);
$display("%d out1: %d", count, out1);
if (count == 16) begin if (count == 16) begin
if (out1 == 15) begin if (out1 == 15) begin
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
@ -49,6 +53,16 @@ module sub0 #(
always_ff @(posedge clk) ff <= in; always_ff @(posedge clk) ff <= in;
assign out = ff; assign out = ff;
logic [7:0] gg;
sub0_sub0 i_sub(.in(ff), .out(gg));
always_ff @(posedge clk) begin
// dotted access under hierarchical block is not allowed ...
$display("%m: i_sub.x: %d", i_sub.x);
// ... Except for ports on a direct hierarchical child
$display("%m: i_sub.out: %d", i_sub.out);
end
endmodule endmodule
module sub1 #( module sub1 #(
@ -56,4 +70,15 @@ module sub1 #(
) ( ) (
input wire T in, output wire T out); `HIER_BLOCK input wire T in, output wire T out); `HIER_BLOCK
assign out = in; assign out = in;
sub1_sub #(T) sub(in, out);
endmodule
module sub0_sub0 (
input wire [7:0] in,
output wire [7:0] out
);
`HIER_BLOCK
wire [7:0] x = in + 1;
assign out = x;
endmodule endmodule