mirror of
https://github.com/verilator/verilator.git
synced 2024-12-29 10:47:34 +00:00
Support for wired nets, wor
/trior
/wand
/triand
. (#5496)
This commit is contained in:
parent
041f6603c3
commit
1710b6bab4
18
src/V3Ast.h
18
src/V3Ast.h
@ -899,6 +899,8 @@ public:
|
||||
SUPPLY1,
|
||||
WIRE,
|
||||
WREAL,
|
||||
TRIAND,
|
||||
TRIOR,
|
||||
TRIWIRE,
|
||||
TRI0,
|
||||
TRI1,
|
||||
@ -919,20 +921,24 @@ public:
|
||||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[]
|
||||
= {"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
|
||||
"WIRE", "WREAL", "TRIWIRE", "TRI0", "TRI1", "PORT", "BLOCKTEMP",
|
||||
"MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
||||
= {"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
|
||||
"WIRE", "WREAL", "TRIAND", "TRIOR", "TRIWIRE", "TRI0", "TRI1",
|
||||
"PORT", "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
||||
return names[m_e];
|
||||
}
|
||||
bool isParam() const { return m_e == GPARAM || m_e == LPARAM; }
|
||||
bool isSignal() const {
|
||||
return (m_e == WIRE || m_e == WREAL || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|
||||
|| m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
|
||||
|| m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR || m_e == TRIOR
|
||||
|| m_e == TRIAND);
|
||||
}
|
||||
bool isNet() const {
|
||||
return (m_e == WIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == SUPPLY0
|
||||
|| m_e == SUPPLY1);
|
||||
|| m_e == SUPPLY1 || m_e == TRIOR || m_e == TRIAND);
|
||||
}
|
||||
bool isWor() const { return (m_e == TRIOR); }
|
||||
bool isWand() const { return (m_e == TRIAND); }
|
||||
bool isWiredNet() const { return (m_e == TRIOR || m_e == TRIAND); }
|
||||
bool isContAssignable() const { // In Verilog, always ok in SystemVerilog
|
||||
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == TRIWIRE
|
||||
|| m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == BLOCKTEMP
|
||||
@ -963,6 +969,8 @@ public:
|
||||
/* SUPPLY1: */ "SUPPLY1",
|
||||
/* WIRE: */ "WIRE",
|
||||
/* WREAL: */ "WIRE",
|
||||
/* TRIAND: */ "TRIAND",
|
||||
/* TRIOR: */ "TRIOR",
|
||||
/* TRIWIRE: */ "TRI",
|
||||
/* TRI0: */ "TRI0",
|
||||
/* TRI1: */ "TRI1",
|
||||
|
@ -2073,6 +2073,9 @@ public:
|
||||
bool isInternal() const { return m_isInternal; }
|
||||
bool isSignal() const { return varType().isSignal(); }
|
||||
bool isNet() const { return varType().isNet(); }
|
||||
bool isWor() const { return varType().isWor(); }
|
||||
bool isWand() const { return varType().isWand(); }
|
||||
bool isWiredNet() const { return varType().isWiredNet(); }
|
||||
bool isTemp() const { return varType().isTemp(); }
|
||||
bool isToggleCoverable() const {
|
||||
return ((isIO() || isSignal())
|
||||
|
@ -914,6 +914,51 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
|| (strength1 <= strength && assignmentOfValueOnAllBits(assignp, 1));
|
||||
}
|
||||
|
||||
AstNodeExpr* newMergeExpr(AstNodeExpr* const lhsp, AstNodeExpr* const rhsp, FileLine* const fl,
|
||||
bool isWor) {
|
||||
AstNodeExpr* expr = nullptr;
|
||||
if (isWor)
|
||||
expr = new AstOr{fl, lhsp, rhsp};
|
||||
else
|
||||
expr = new AstAnd{fl, lhsp, rhsp};
|
||||
return expr;
|
||||
}
|
||||
|
||||
void mergeWiredNetsAssignments() {
|
||||
// Support for WOR/TRIOR/WAND/TRIAND, by merging the Assignments for the
|
||||
// same Net (merge by or for WOR/TIOR and merge by and for WAND/TRIAND).
|
||||
for (auto& varpAssigns : m_assigns) {
|
||||
Assigns& assigns = varpAssigns.second;
|
||||
if (assigns.size() > 1) {
|
||||
AstVar* varp = varpAssigns.first;
|
||||
if (varp->isWiredNet()) {
|
||||
auto it = assigns.begin();
|
||||
AstAssignW* const assignWp0 = *it;
|
||||
FileLine* const fl = assignWp0->fileline();
|
||||
AstNodeExpr* wExp = nullptr;
|
||||
while (++it != assigns.end()) {
|
||||
AstAssignW* assignWpi = *it;
|
||||
if (!wExp) {
|
||||
wExp = newMergeExpr(assignWp0->rhsp()->cloneTreePure(false),
|
||||
assignWpi->rhsp()->cloneTreePure(false), fl,
|
||||
varp->isWor());
|
||||
} else {
|
||||
wExp = newMergeExpr(wExp, assignWpi->rhsp()->cloneTreePure(false), fl,
|
||||
varp->isWor());
|
||||
}
|
||||
VL_DO_DANGLING((assignWpi->unlinkFrBack()->deleteTree()), assignWpi);
|
||||
}
|
||||
AstVarRef* const wVarRef = new AstVarRef{fl, varp, VAccess::WRITE};
|
||||
AstAssignW* const wAssignp = new AstAssignW{fl, wVarRef, wExp};
|
||||
assignWp0->replaceWith(wAssignp);
|
||||
VL_DO_DANGLING(pushDeletep(assignWp0), assignWp0);
|
||||
assigns.clear();
|
||||
assigns.push_back(wAssignp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeNotStrongerAssignments(Assigns& assigns, AstAssignW* strongestp,
|
||||
uint8_t greatestKnownStrength) {
|
||||
// Weaker assignments are these assignments that can't change the final value of the net.
|
||||
@ -1776,6 +1821,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
iterateChildren(nodep);
|
||||
m_graphing = false;
|
||||
}
|
||||
// Merge the assignments for very Wired net LHS : wor, trior, wand and triand
|
||||
mergeWiredNetsAssignments();
|
||||
// Remove all assignments not stronger than the strongest uniform constant
|
||||
removeAssignmentsNotStrongerThanUniformConstant();
|
||||
// Use graph to find tristate signals
|
||||
|
@ -1994,12 +1994,12 @@ net_type: // ==IEEE: net_type
|
||||
| yTRI { VARDECL(TRIWIRE); }
|
||||
| yTRI0 { VARDECL(TRI0); }
|
||||
| yTRI1 { VARDECL(TRI1); }
|
||||
| yTRIAND { VARDECL(WIRE); BBUNSUP($1, "Unsupported: triand"); }
|
||||
| yTRIOR { VARDECL(WIRE); BBUNSUP($1, "Unsupported: trior"); }
|
||||
| yTRIAND { VARDECL(TRIAND); }
|
||||
| yTRIOR { VARDECL(TRIOR); }
|
||||
| yTRIREG { VARDECL(WIRE); BBUNSUP($1, "Unsupported: trireg"); }
|
||||
| yWAND { VARDECL(WIRE); BBUNSUP($1, "Unsupported: wand"); }
|
||||
| yWAND { VARDECL(TRIAND); }
|
||||
| yWIRE { VARDECL(WIRE); }
|
||||
| yWOR { VARDECL(WIRE); BBUNSUP($1, "Unsupported: wor"); }
|
||||
| yWOR { VARDECL(TRIOR); }
|
||||
// // VAMS - somewhat hackish
|
||||
| yWREAL { VARDECL(WREAL); }
|
||||
;
|
||||
|
@ -1,8 +0,0 @@
|
||||
%Error-UNSUPPORTED: t/t_wire_triand.v:11:4: Unsupported: triand
|
||||
11 | triand ta;
|
||||
| ^~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_wire_triand.v:12:4: Unsupported: trior
|
||||
12 | trior to;
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
@ -1,14 +0,0 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module for SystemVerilog 'alias'
|
||||
//
|
||||
// Simple bi-directional alias test.
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
triand ta;
|
||||
trior to;
|
||||
|
||||
endmodule
|
@ -9,8 +9,10 @@
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
71
test_regress/t/t_wired_net_test.v
Executable file
71
test_regress/t/t_wired_net_test.v
Executable file
@ -0,0 +1,71 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`define stop $stop
|
||||
`define checkb(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='b%x exp='b%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
|
||||
module t(
|
||||
clk
|
||||
/*AUTOARG*/);
|
||||
input clk;
|
||||
wor [3:0] ptrior1;
|
||||
trior [3:0] ptrior2;
|
||||
wand [3:0] ptriand1;
|
||||
triand [3:0] ptriand2;
|
||||
wire [3:0] z1;
|
||||
wire [3:0] z2;
|
||||
wire [3:0] tri_z1;
|
||||
wire [3:0] tri_z2;
|
||||
logic [3:0] x;
|
||||
logic [3:0] y;
|
||||
logic [3:0] tri_x;
|
||||
logic [3:0] tri_y;
|
||||
logic [3:0] tri_x_dat;
|
||||
logic [3:0] tri_y_dat;
|
||||
logic [3:0] tri_x_en;
|
||||
logic [3:0] tri_y_en;
|
||||
assign ptrior1 = x & y;
|
||||
assign ptrior1 = x + y;
|
||||
assign ptrior2 = tri_x & tri_y;
|
||||
assign ptrior2 = tri_x + tri_y;
|
||||
assign ptriand1 = x & y;
|
||||
assign ptriand1 = x + y;
|
||||
assign ptriand2 = tri_x & tri_y;
|
||||
assign ptriand2 = tri_x + tri_y;
|
||||
assign z1 = (x & y) | (x + y);
|
||||
assign z2 = (x & y) & (x + y);
|
||||
assign tri_z1 = (tri_x & tri_y) | (tri_x + tri_y);
|
||||
assign tri_z2 = (tri_x & tri_y) & (tri_x + tri_y);
|
||||
integer cyc = 0;
|
||||
integer xz_index = 0;
|
||||
integer xz_num = 0;
|
||||
integer i;
|
||||
assign tri_x[0] = tri_x_en[0] ? tri_x_dat[0] : 1'bz;
|
||||
assign tri_x[1] = tri_x_en[1] ? tri_x_dat[1] : 1'bz;
|
||||
assign tri_x[2] = tri_x_en[2] ? tri_x_dat[2] : 1'bz;
|
||||
assign tri_x[3] = tri_x_en[3] ? tri_x_dat[3] : 1'bz;
|
||||
assign tri_y[0] = tri_y_en[0] ? tri_y_dat[0] : 1'bz;
|
||||
assign tri_y[1] = tri_y_en[1] ? tri_y_dat[1] : 1'bz;
|
||||
assign tri_y[2] = tri_y_en[2] ? tri_y_dat[2] : 1'bz;
|
||||
assign tri_y[3] = tri_y_en[3] ? tri_y_dat[3] : 1'bz;
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
x = {$random}[3:0];
|
||||
y = {$random}[3:0];
|
||||
tri_x_dat = {$random}[3:0];
|
||||
tri_y_dat = {$random}[3:0];
|
||||
tri_x_en = {$random}[3:0];
|
||||
tri_y_en = {$random}[3:0];
|
||||
`checkb(ptrior1, z1);
|
||||
`checkb(ptrior2, tri_z1);
|
||||
`checkb(ptriand1, z2);
|
||||
`checkb(ptriand2, tri_z2);
|
||||
if (cyc == 20) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user