Support inout clocking items (#5160)

This commit is contained in:
Arkadiusz Kozdra 2024-06-07 14:30:58 +02:00 committed by GitHub
parent 3f886f7c61
commit 1dbf1be3e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 116 additions and 23 deletions

View File

@ -158,6 +158,13 @@ private:
iterateChildren(nodep);
}
void visit(AstClockingItem* const nodep) override {
// Get a ref to the sampled/driven variable
AstVar* const varp = nodep->varp();
if (!varp) {
// Unused item
pushDeletep(nodep->unlinkFrBack());
return;
}
FileLine* const flp = nodep->fileline();
V3Const::constifyEdit(nodep->skewp());
if (!VN_IS(nodep->skewp(), Const)) {
@ -168,9 +175,7 @@ private:
AstConst* const skewp = VN_AS(nodep->skewp(), Const);
if (skewp->num().isNegative()) skewp->v3error("Skew cannot be negative");
AstNodeExpr* const exprp = nodep->exprp();
// Get a ref to the sampled/driven variable
AstVar* const varp = nodep->varp()->unlinkFrBack();
m_clockingp->addVarsp(varp);
m_clockingp->addVarsp(varp->unlinkFrBack());
varp->user1p(nodep);
if (nodep->direction() == VDirection::OUTPUT) {
AstVarRef* const skewedRefp = new AstVarRef{flp, varp, VAccess::READ};
@ -224,6 +229,7 @@ private:
AstVar* const queueVarp = new AstVar{
flp, VVarType::MODULETEMP,
"__Vqueue__" + m_clockingp->name() + "__DOT__" + varp->name(), queueDtp};
queueVarp->lifetime(VLifetime::STATIC);
m_clockingp->addNextHere(queueVarp);
// Create a process like this:
// always queue.push(<sampled var>);
@ -290,6 +296,8 @@ private:
const std::string delayName = m_cycleDlyNames.get(nodep);
AstVar* const cntVarp = new AstVar{flp, VVarType::BLOCKTEMP, delayName + "__counter",
nodep->findBasicDType(VBasicDTypeKwd::UINT32)};
cntVarp->lifetime(VLifetime::AUTOMATIC);
cntVarp->funcLocal(true);
AstBegin* const beginp = new AstBegin{flp, delayName + "__block", cntVarp, false, true};
beginp->addStmtsp(new AstAssign{flp, new AstVarRef{flp, cntVarp, VAccess::WRITE}, valuep});
beginp->addStmtsp(new AstWhile{

View File

@ -956,6 +956,7 @@ class AstClockingItem final : public AstNode {
// @astgen op2 := exprp : Optional[AstNodeExpr]
// @astgen op3 := assignp : Optional[AstAssign]
// @astgen op4 := varp : Optional[AstVar]
// @astgen ptr := m_outputp : Optional[AstClockingItem]
VDirection m_direction;
public:
@ -971,6 +972,9 @@ public:
}
ASTGEN_MEMBERS_AstClockingItem;
VDirection direction() const { return m_direction; }
AstClockingItem* outputp() const { return m_outputp; }
void outputp(AstClockingItem* outputp) { m_outputp = outputp; }
bool maybePointedTo() const override { return true; }
};
class AstConstPool final : public AstNode {
// Container for const static data

View File

@ -1211,6 +1211,23 @@ class LinkDotFindVisitor final : public VNVisitor {
foundp = m_modSymp; // Conflicts with modname?
}
AstVar* const findvarp = foundp ? VN_CAST(foundp->nodep(), Var) : nullptr;
// clocking items can have duplicate names (inout)
if (findvarp && VN_IS(findvarp->backp(), ClockingItem)
&& VN_IS(nodep->backp(), ClockingItem)) {
AstClockingItem* const itemp = VN_AS(nodep->backp(), ClockingItem);
AstClockingItem* const finditemp = VN_AS(findvarp->backp(), ClockingItem);
UINFO(4, "ClockCompl: " << itemp << " ;; " << finditemp << endl);
UINFO(4, "ClockCompV: " << nodep << " ;; " << findvarp << endl);
if (*itemp->exprp()->fileline() == *finditemp->exprp()->fileline()) {
UASSERT_OBJ(finditemp->direction() == VDirection::INPUT
&& itemp->direction() == VDirection::OUTPUT,
itemp, "Input after output?");
// pretend nothing found and rename
foundp = nullptr;
nodep->name("__Voutput_" + nodep->name());
finditemp->outputp(itemp);
}
}
bool ins = false;
if (!foundp) {
ins = true;
@ -2181,6 +2198,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
AstVar* const eventp = new AstVar{
clockingp->fileline(), VVarType::MODULETEMP, clockingp->name(), VFlagChildDType{},
new AstBasicDType{clockingp->fileline(), VBasicDTypeKwd::EVENT}};
eventp->lifetime(VLifetime::STATIC);
clockingp->eventp(eventp);
// Trigger the clocking event in Observed (IEEE 1800-2023 14.13)
clockingp->addNextHere(new AstAlwaysObserved{

View File

@ -50,6 +50,10 @@ class LinkLValueVisitor final : public VNVisitor {
// so it is needed to check only if m_setContinuously is true
if (m_setStrengthSpecified) nodep->varp()->hasStrengthAssignment(true);
}
if (const AstClockingItem* itemp = VN_CAST(nodep->varp()->backp(), ClockingItem)) {
UINFO(5, "ClkOut " << nodep << endl);
if (itemp->outputp()) nodep->varp(itemp->outputp()->varp());
}
if (m_setForcedByCode) {
nodep->varp()->setForcedByCode();
} else if (!nodep->varp()->isFuncLocal() && nodep->varp()->isReadOnly()) {

View File

@ -5918,11 +5918,11 @@ clocking_item<clockingItemp>: // IEEE: clocking_item
| yOUTPUT clocking_skewE list_of_clocking_decl_assign ';'
{ $$ = GRAMMARP->makeClockingItemList($<fl>1, VDirection::OUTPUT, $2, $3); }
| yINPUT clocking_skewE yOUTPUT clocking_skewE list_of_clocking_decl_assign ';'
{ $$ = nullptr;
BBUNSUP($5, "Unsupported: Mixed input/output clocking items"); }
{ $$ = GRAMMARP->makeClockingItemList($<fl>1, VDirection::INPUT, $2, $5->cloneTree(true));
$$->addNext(GRAMMARP->makeClockingItemList($<fl>3, VDirection::OUTPUT, $4, $5)); }
| yINOUT list_of_clocking_decl_assign ';'
{ $$ = nullptr;
BBUNSUP($1, "Unsupported: 'inout' clocking items"); }
{ $$ = GRAMMARP->makeClockingItemList($<fl>1, VDirection::INPUT, nullptr, $2->cloneTree(true));
$$->addNext(GRAMMARP->makeClockingItemList($<fl>1, VDirection::OUTPUT, nullptr, $2)); }
| assertion_item_declaration
{ $$ = nullptr;
BBUNSUP($1, "Unsupported: assertion items in clocking blocks"); }

View File

@ -0,0 +1,23 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2023 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
scenarios(simulator => 1);
compile(
verilator_flags2 => ["--exe --main --timing"],
make_main => 0,
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,44 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2023 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
module t;
logic clk = 0, foo = 0, bar = 0;
always #5 clk = ~clk;
clocking cb @(posedge clk);
input #11 output #2 foo;
inout bar;
endclocking
initial begin
cb.foo <= 1;
cb.bar <= 1;
if (foo != 0 || cb.foo != 0) $stop;
if (bar != 0 || cb.bar != 0) $stop;
@(posedge bar)
if ($time != 5) $stop;
if (foo != 0 || cb.foo != 0) $stop;
if (cb.bar != 0) $stop;
#1
if (foo != 0 || cb.foo != 0) $stop;
if (cb.bar != 1) $stop;
@(posedge foo)
if ($time != 7) $stop;
if (cb.foo != 0) $stop;
#9 // $time == 16
if (cb.foo != 0) $stop;
#10 // $time == 26
if (cb.foo != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -1,17 +1,11 @@
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:14:26: Unsupported: Mixed input/output clocking items
14 | input #1 output #1step x;
| ^
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:14:15: Unsupported: clocking event edge override
14 | output posedge #1 a;
| ^~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:15:8: Unsupported: 'inout' clocking items
15 | inout y;
| ^~~~~
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:15:15: Unsupported: clocking event edge override
15 | output negedge #1 b;
| ^~~~~~~
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:16:15: Unsupported: clocking event edge override
16 | output posedge #1 a;
| ^~~~~~~
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:17:15: Unsupported: clocking event edge override
17 | output negedge #1 b;
| ^~~~~~~
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:18:15: Unsupported: clocking event edge override
18 | output edge #1 b;
16 | output edge #1 b;
| ^~~~
%Error: Exiting due to

View File

@ -10,9 +10,7 @@ module t(/*AUTOARG*/
);
input clk;
global clocking cb @(posedge clk);
input #1 output #1step x;
inout y;
clocking cb @(posedge clk);
output posedge #1 a;
output negedge #1 b;
output edge #1 b;