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:
parent
68b227065e
commit
0ead54b17e
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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: '"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue