Add handling of tristate select/extend (#3604)
This commit is contained in:
parent
4db998d357
commit
46b8dca360
|
|
@ -493,6 +493,47 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
}
|
||||
return VN_AS(invarp->user1p(), Var);
|
||||
}
|
||||
AstConst* getNonZConstp(AstConst* const constp) {
|
||||
FileLine* const fl = constp->fileline();
|
||||
V3Number numz{constp, constp->width()};
|
||||
numz.opBitsZ(constp->num()); // Z->1, else 0
|
||||
V3Number numz0{constp, constp->width()};
|
||||
numz0.opNot(numz); // Z->0, else 1
|
||||
return new AstConst{fl, numz0};
|
||||
}
|
||||
AstNode* getEnExprBasedOnOriginalp(AstNode* const nodep) {
|
||||
if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) {
|
||||
return new AstVarRef{varrefp->fileline(), getCreateEnVarp(varrefp->varp()),
|
||||
VAccess::READ};
|
||||
} else if (AstConst* const constp = VN_CAST(nodep, Const)) {
|
||||
return getNonZConstp(constp);
|
||||
} else if (AstExtend* const extendp = VN_CAST(nodep, Extend)) {
|
||||
// Extend inserts 0 at the beginning. 0 in __en variable means that this bit equals z,
|
||||
// so in order to preserve the value of the original AstExtend node we should insert 1
|
||||
// instead of 0. To extend __en expression we have to negate its lhsp() and then negate
|
||||
// whole extend.
|
||||
|
||||
// Unlink lhsp before copying to save unnecessary copy of lhsp
|
||||
AstNode* const lhsp = extendp->lhsp()->unlinkFrBack();
|
||||
AstExtend* const enExtendp = extendp->cloneTree(false);
|
||||
extendp->lhsp(lhsp);
|
||||
AstNode* const enLhsp = getEnExprBasedOnOriginalp(lhsp);
|
||||
enExtendp->lhsp(new AstNot{enLhsp->fileline(), enLhsp});
|
||||
return new AstNot{enExtendp->fileline(), enExtendp};
|
||||
} else if (AstSel* const selp = VN_CAST(nodep, Sel)) {
|
||||
AstNode* const fromp = selp->fromp()->unlinkFrBack();
|
||||
AstSel* const enSelp = selp->cloneTree(false);
|
||||
selp->fromp(fromp);
|
||||
AstNode* const enFromp = getEnExprBasedOnOriginalp(fromp);
|
||||
enSelp->fromp(enFromp);
|
||||
return enSelp;
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported tristate construct: " << nodep->prettyTypeName()
|
||||
<< " in function " << __func__);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
AstVar* getCreateOutVarp(AstVar* invarp) {
|
||||
// Return the master __out for the specified input variable
|
||||
if (!invarp->user4p()) {
|
||||
|
|
@ -959,14 +1000,10 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
} else if (m_tgraph.isTristate(nodep)) {
|
||||
m_tgraph.didProcess(nodep);
|
||||
FileLine* const fl = nodep->fileline();
|
||||
V3Number numz(nodep, nodep->width());
|
||||
numz.opBitsZ(nodep->num()); // Z->1, else 0
|
||||
V3Number numz0(nodep, nodep->width());
|
||||
numz0.opNot(numz); // Z->0, else 1
|
||||
V3Number num1(nodep, nodep->width());
|
||||
num1.opAnd(nodep->num(), numz0); // 01X->01X, Z->0
|
||||
AstConst* const newconstp = new AstConst(fl, num1);
|
||||
AstConst* const enp = new AstConst(fl, numz0);
|
||||
AstConst* const enp = getNonZConstp(nodep);
|
||||
V3Number num1{nodep, nodep->width()};
|
||||
num1.opAnd(nodep->num(), enp->num()); // 01X->01X, Z->0
|
||||
AstConst* const newconstp = new AstConst{fl, num1};
|
||||
nodep->replaceWith(newconstp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
newconstp->user1p(enp); // Propagate up constant with non-Z bits as 1
|
||||
|
|
@ -1263,23 +1300,27 @@ class TristateVisitor final : public TristateBaseVisitor {
|
|||
UINFO(9, dbgState() << nodep << endl);
|
||||
// Constification always moves const to LHS
|
||||
AstConst* const constp = VN_CAST(nodep->lhsp(), Const);
|
||||
AstVarRef* const varrefp = VN_CAST(nodep->rhsp(), VarRef); // Input variable
|
||||
if (constp && constp->user1p() && varrefp) {
|
||||
if (constp && constp->user1p()) {
|
||||
// 3'b1z0 -> ((3'b101 == in__en) && (3'b100 == in))
|
||||
varrefp->unlinkFrBack();
|
||||
AstNode* const rhsp = nodep->rhsp();
|
||||
rhsp->unlinkFrBack();
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNode* enRhsp;
|
||||
if (rhsp->user1p()) {
|
||||
enRhsp = rhsp->user1p();
|
||||
rhsp->user1p(nullptr);
|
||||
} else {
|
||||
enRhsp = getEnExprBasedOnOriginalp(rhsp);
|
||||
}
|
||||
const V3Number oneIfEn
|
||||
= VN_AS(constp->user1p(), Const)
|
||||
->num(); // visit(AstConst) already split into en/ones
|
||||
const V3Number& oneIfEnOne = constp->num();
|
||||
AstVar* const envarp = getCreateEnVarp(varrefp->varp());
|
||||
AstNode* newp
|
||||
= new AstLogAnd(fl,
|
||||
new AstEq(fl, new AstConst(fl, oneIfEn),
|
||||
new AstVarRef(fl, envarp, VAccess::READ)),
|
||||
= new AstLogAnd{fl, new AstEq{fl, new AstConst{fl, oneIfEn}, enRhsp},
|
||||
// Keep the caseeq if there are X's present
|
||||
new AstEqCase(fl, new AstConst(fl, oneIfEnOne), varrefp));
|
||||
if (neq) newp = new AstLogNot(fl, newp);
|
||||
new AstEqCase{fl, new AstConst{fl, oneIfEnOne}, rhsp}};
|
||||
if (neq) newp = new AstLogNot{fl, newp};
|
||||
UINFO(9, " newceq " << newp << endl);
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "-caseeq-old: ");
|
||||
if (debug() >= 9) newp->dumpTree(cout, "-caseeq-new: ");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
%Error-UNSUPPORTED: t/t_tri_and_eqcase.v:9:28: Unsupported tristate construct: AND in function getEnExprBasedOnOriginalp
|
||||
9 | logic b = 1'z === (clk1 & clk2);
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Internal Error: t/t_tri_and_eqcase.v:9:18: ../V3Ast.cpp:#: Null item passed to setOp2p
|
||||
9 | logic b = 1'z === (clk1 & clk2);
|
||||
| ^~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html for more assistance.
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 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(vlt => 1);
|
||||
|
||||
lint(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (clk1, clk2);
|
||||
input wire clk1, clk2;
|
||||
logic b = 1'z === (clk1 & clk2);
|
||||
|
||||
always begin
|
||||
if (!b) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2022 by Antmicro Ltd. 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(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
wire [3:0] a = 4'b11z1;
|
||||
logic b = 1'bz === a[1];
|
||||
logic c = 1'bz === a[2];
|
||||
logic d = 2'bzz === 2'(a[1]);
|
||||
logic e = 2'b0z === 2'(a[1]);
|
||||
|
||||
|
||||
always begin
|
||||
if (b && !c && !d && e) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
else begin
|
||||
$write("Error: b = %b, c = %b, d = %b, e = %b ", b, c, d, e);
|
||||
$write("expected: b = 1, c = 0, d = 0, e = 1\n");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue