Support method calls on a sub-interface via a virtual interface
This commit is contained in:
parent
ed143a6cc2
commit
49e2002704
|
|
@ -3789,7 +3789,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (!varp->didWidth()) userIterate(varp, nullptr);
|
||||
nodep->dtypep(foundp->dtypep());
|
||||
nodep->varp(varp);
|
||||
AstIface* const ifacep = adtypep->ifacep();
|
||||
AstIface* const ifacep = adtypep->ifaceViaCellp();
|
||||
varp->sensIfacep(ifacep);
|
||||
nodep->didWidth(true);
|
||||
return;
|
||||
|
|
@ -3830,7 +3830,26 @@ class WidthVisitor final : public VNVisitor {
|
|||
UASSERT_OBJ(viftopVarp, nodep,
|
||||
"No __Viftop variable for sub-interface cell");
|
||||
if (!viftopVarp->didWidth()) userIterate(viftopVarp, nullptr);
|
||||
nodep->dtypep(viftopVarp->dtypep());
|
||||
AstNodeDType* subDtypep = viftopVarp->dtypep();
|
||||
if (adtypep->isVirtual()) {
|
||||
// A sub-interface selected through a virtual interface
|
||||
// handle is itself a virtual reference (a runtime
|
||||
// instance pointer), not a static instance. Mark the
|
||||
// dtype virtual so a method call on it dispatches per
|
||||
// instance instead of inlining to one fixed scope.
|
||||
AstIfaceRefDType* const subRefp
|
||||
= VN_CAST(subDtypep->skipRefp(), IfaceRefDType);
|
||||
if (subRefp) {
|
||||
AstIfaceRefDType* const newDtypep = new AstIfaceRefDType{
|
||||
nodep->fileline(), subRefp->cellName(), subRefp->ifaceName()};
|
||||
newDtypep->ifacep(subRefp->ifacep());
|
||||
newDtypep->cellp(subRefp->cellp());
|
||||
newDtypep->isVirtual(true);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(newDtypep);
|
||||
subDtypep = newDtypep;
|
||||
}
|
||||
}
|
||||
nodep->dtypep(subDtypep);
|
||||
nodep->varp(viftopVarp);
|
||||
viftopVarp->sensIfacep(VN_AS(cellp->modp(), Iface));
|
||||
nodep->didWidth(true);
|
||||
|
|
@ -4781,16 +4800,9 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
void methodCallIfaceRef(AstMethodCall* nodep, AstIfaceRefDType* adtypep) {
|
||||
AstIface* const ifacep = adtypep->ifacep();
|
||||
if (!ifacep) {
|
||||
// A sub-interface reached through a virtual interface handle has a
|
||||
// ref dtype with cellp set but ifacep null; the per-instance binding
|
||||
// is not modelled, so the call cannot be resolved to one instance.
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: method call on a sub-interface "
|
||||
"accessed through a virtual interface");
|
||||
nodep->dtypeSetVoid();
|
||||
return;
|
||||
}
|
||||
// ifaceViaCellp() resolves the interface via cellp when ifacep is null,
|
||||
// as for a sub-interface selected through a virtual interface handle.
|
||||
AstIface* const ifacep = adtypep->ifaceViaCellp();
|
||||
UINFO(5, __FUNCTION__ << ":" << nodep);
|
||||
if (AstNodeFTask* const ftaskp
|
||||
= VN_CAST(m_memberMap.findMember(ifacep, nodep->name()), NodeFTask)) {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@
|
|||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// 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 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
|
||||
|
||||
interface inner_if;
|
||||
logic [7:0] cnt = 0;
|
||||
function automatic void bump();
|
||||
cnt = cnt + 1;
|
||||
endfunction
|
||||
function automatic logic [7:0] get();
|
||||
return cnt;
|
||||
endfunction
|
||||
task automatic addn(input logic [7:0] n);
|
||||
cnt = cnt + n;
|
||||
endtask
|
||||
endinterface
|
||||
|
||||
interface mid_if;
|
||||
inner_if sub ();
|
||||
endinterface
|
||||
|
||||
interface data_if;
|
||||
logic [7:0] val = 0;
|
||||
endinterface
|
||||
|
||||
interface outer_if;
|
||||
inner_if a ();
|
||||
inner_if b ();
|
||||
mid_if m ();
|
||||
data_if d ();
|
||||
endinterface
|
||||
|
||||
class driver_c;
|
||||
virtual outer_if vif;
|
||||
task run();
|
||||
vif.a.bump(); // sibling a: void function, +1
|
||||
vif.b.bump(); // sibling b: void function, +1
|
||||
vif.b.addn(8'd5); // sibling b: task with arg, +5
|
||||
vif.m.sub.bump(); // two-level nesting, +1
|
||||
vif.d.val = 8'd99; // sub-interface variable write via vif (no method)
|
||||
endtask
|
||||
function logic [7:0] read_a();
|
||||
return vif.a.get(); // function returning value via vif sub-interface
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t;
|
||||
outer_if oif ();
|
||||
driver_c drv;
|
||||
initial begin
|
||||
drv = new();
|
||||
drv.vif = oif;
|
||||
drv.run();
|
||||
// Per-instance dispatch: a, b and m.sub are distinct instances.
|
||||
`checkd(oif.a.cnt, 8'd1)
|
||||
`checkd(oif.b.cnt, 8'd6)
|
||||
`checkd(oif.m.sub.cnt, 8'd1)
|
||||
`checkd(drv.read_a(), 8'd1)
|
||||
`checkd(oif.d.val, 8'd99)
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
%Error-UNSUPPORTED: t/t_interface_virtual_sub_iface_method_bad.v:21:16: Unsupported: method call on a sub-interface accessed through a virtual interface
|
||||
: ... note: In instance 't'
|
||||
21 | vif.sub_if.set_active();
|
||||
| ^~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
// 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
|
||||
|
||||
interface inner_if;
|
||||
logic active = 1'b0;
|
||||
function automatic void set_active();
|
||||
active = 1'b1;
|
||||
endfunction
|
||||
endinterface
|
||||
|
||||
interface outer_if;
|
||||
inner_if sub_if ();
|
||||
endinterface
|
||||
|
||||
class cfg_c;
|
||||
virtual outer_if vif;
|
||||
function void doit();
|
||||
vif.sub_if.set_active();
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t;
|
||||
outer_if oif ();
|
||||
cfg_c cfg;
|
||||
initial begin
|
||||
cfg = new();
|
||||
cfg.vif = oif;
|
||||
cfg.doit();
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue