forked from github/verilator
Add split_var metacomment to assist UNOPTFLAT fixes, #2066.
This commit is contained in:
parent
c6b755a12e
commit
4878fe3a1f
2
Changes
2
Changes
@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
|||||||
|
|
||||||
* Verilator 4.029 devel
|
* Verilator 4.029 devel
|
||||||
|
|
||||||
|
** Add split_var metacomment to assist UNOPTFLAT fixes, #2066. [Yutetsu TAKATSUKASA]
|
||||||
|
|
||||||
*** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel]
|
*** Add +verilator+noassert flag to disable assertion checking. [Tobias Wölfel]
|
||||||
|
|
||||||
*** Add check for assertOn for asserts, #2162. [Tobias Wölfel]
|
*** Add check for assertOn for asserts, #2162. [Tobias Wölfel]
|
||||||
|
@ -3420,6 +3420,33 @@ behavior. See the test_regress/t/t_dpi_display.v file for an example.
|
|||||||
Same as C<sformat> in configuration files, see L</"CONFIGURATION FILES">
|
Same as C<sformat> in configuration files, see L</"CONFIGURATION FILES">
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
|
=item /*verilator split_var*/
|
||||||
|
|
||||||
|
Attached to a variable or a net declaration to break the variable into
|
||||||
|
multiple pieces typically to resolve UNOPTFLAT performance issues.
|
||||||
|
Typically the variables to attach this to are recommeded by Verilator
|
||||||
|
itself, see UNOPTFLAT below.
|
||||||
|
|
||||||
|
For example, Verilator will internally convert a variable with the
|
||||||
|
metacomment such as:
|
||||||
|
|
||||||
|
logic [7:0] x [0:1] /*verilator split_var*/;
|
||||||
|
|
||||||
|
To:
|
||||||
|
|
||||||
|
logic [7:0] x__BRA__0__KET__ /*verilator split_var*/;
|
||||||
|
logic [7:0] x__BRA__1__KET__ /*verilator split_var*/;
|
||||||
|
|
||||||
|
Note that the generated packed variables retain the split_var metacomment
|
||||||
|
because they may be split into further smaller pieces accorting to the
|
||||||
|
access patterns.
|
||||||
|
|
||||||
|
This only supports unpacked arrays, packed arrays, and packed structs of
|
||||||
|
integer types (reg, logic, bit, byte, int...); otherwise if a split was
|
||||||
|
requested but cannot occur a SPLITVAR warning is issued. Splitting large
|
||||||
|
arrays may slow donw the Verilation speed, so use this only on variables
|
||||||
|
that require it.
|
||||||
|
|
||||||
=item /*verilator tag <text...>*/
|
=item /*verilator tag <text...>*/
|
||||||
|
|
||||||
Attached after a variable or structure member to indicate opaque (to
|
Attached after a variable or structure member to indicate opaque (to
|
||||||
@ -4383,6 +4410,29 @@ Ignoring this warning may make Verilator simulations differ from other
|
|||||||
simulators, if the increased precision of real affects your model or DPI
|
simulators, if the increased precision of real affects your model or DPI
|
||||||
calls.
|
calls.
|
||||||
|
|
||||||
|
=item SPLITVAR
|
||||||
|
|
||||||
|
Warns that a variable with a C<split_var> metacomment was not split.
|
||||||
|
Some possible reasons for this are:
|
||||||
|
|
||||||
|
* The datatype of the variable is not supported for splitting. (e.g. is a
|
||||||
|
real).
|
||||||
|
|
||||||
|
* The access pattern of the variable can not be determined
|
||||||
|
statically. (e.g. is accessed as a memory).
|
||||||
|
|
||||||
|
* The index of the array exceeds the array size.
|
||||||
|
|
||||||
|
* The variable is accessed from outside using dotted reference.
|
||||||
|
(e.g. top.instance0.variable0 = 1).
|
||||||
|
|
||||||
|
* The variable is not declared in a module, but in a package or an
|
||||||
|
interface.
|
||||||
|
|
||||||
|
* The variable is a parameter, localparam, genvar, or queue.
|
||||||
|
|
||||||
|
* The variable is tirstate or bidirectional. (e.g. inout or ref).
|
||||||
|
|
||||||
=item STMTDLY
|
=item STMTDLY
|
||||||
|
|
||||||
Warns that you have a statement with a delayed time in front of it, for
|
Warns that you have a statement with a delayed time in front of it, for
|
||||||
@ -4514,6 +4564,11 @@ being generated from an always statement that consumed high bits of the
|
|||||||
same bus processed by another series of always blocks. The fix is the
|
same bus processed by another series of always blocks. The fix is the
|
||||||
same; split it into two separate signals generated from each block.
|
same; split it into two separate signals generated from each block.
|
||||||
|
|
||||||
|
Another way to resolve this warning is to add a C<split_var> metacomment
|
||||||
|
described above. This will cause the variable to be split internally,
|
||||||
|
potentially resolving the conflict. If you run with --report-unoptflat
|
||||||
|
Verilator will suggest possible candidates for C<split_var>.
|
||||||
|
|
||||||
The UNOPTFLAT warning may also be due to clock enables, identified from the
|
The UNOPTFLAT warning may also be due to clock enables, identified from the
|
||||||
reported path going through a clock gating cell. To fix these, use the
|
reported path going through a clock gating cell. To fix these, use the
|
||||||
clock_enable meta comment described above.
|
clock_enable meta comment described above.
|
||||||
|
@ -233,6 +233,7 @@ RAW_OBJS = \
|
|||||||
V3Slice.o \
|
V3Slice.o \
|
||||||
V3Split.o \
|
V3Split.o \
|
||||||
V3SplitAs.o \
|
V3SplitAs.o \
|
||||||
|
V3SplitVar.o \
|
||||||
V3Stats.o \
|
V3Stats.o \
|
||||||
V3StatsReport.o \
|
V3StatsReport.o \
|
||||||
V3String.o \
|
V3String.o \
|
||||||
|
@ -326,7 +326,8 @@ public:
|
|||||||
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
|
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
|
||||||
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
|
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
|
||||||
VAR_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
|
VAR_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
|
||||||
VAR_NO_CLOCKER // V3LinkParse moves to AstVar::attrClocker
|
VAR_NO_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
|
||||||
|
VAR_SPLIT_VAR // V3LinkParse moves to AstVar::attrSplitVar
|
||||||
};
|
};
|
||||||
enum en m_e;
|
enum en m_e;
|
||||||
const char* ascii() const {
|
const char* ascii() const {
|
||||||
@ -342,7 +343,7 @@ public:
|
|||||||
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
|
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
|
||||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
|
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
|
||||||
"VAR_NO_CLOCKER"
|
"VAR_NO_CLOCKER", "VAR_SPLIT_VAR"
|
||||||
};
|
};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
}
|
}
|
||||||
|
@ -1456,6 +1456,7 @@ private:
|
|||||||
bool m_attrScBv:1; // User force bit vector attribute
|
bool m_attrScBv:1; // User force bit vector attribute
|
||||||
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
|
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
|
||||||
bool m_attrSFormat:1;// User sformat attribute
|
bool m_attrSFormat:1;// User sformat attribute
|
||||||
|
bool m_attrSplitVar:1; // declared with split_var metacomment
|
||||||
bool m_fileDescr:1; // File descriptor
|
bool m_fileDescr:1; // File descriptor
|
||||||
bool m_isConst:1; // Table contains constant data
|
bool m_isConst:1; // Table contains constant data
|
||||||
bool m_isStatic:1; // Static variable
|
bool m_isStatic:1; // Static variable
|
||||||
@ -1478,7 +1479,7 @@ private:
|
|||||||
m_sigUserRdPublic = false; m_sigUserRWPublic = false;
|
m_sigUserRdPublic = false; m_sigUserRWPublic = false;
|
||||||
m_funcLocal = false; m_funcReturn = false;
|
m_funcLocal = false; m_funcReturn = false;
|
||||||
m_attrClockEn = false; m_attrScBv = false;
|
m_attrClockEn = false; m_attrScBv = false;
|
||||||
m_attrIsolateAssign = false; m_attrSFormat = false;
|
m_attrIsolateAssign = false; m_attrSFormat = false; m_attrSplitVar = false;
|
||||||
m_fileDescr = false; m_isConst = false;
|
m_fileDescr = false; m_isConst = false;
|
||||||
m_isStatic = false; m_isPulldown = false; m_isPullup = false;
|
m_isStatic = false; m_isPulldown = false; m_isPullup = false;
|
||||||
m_isIfaceParent = false; m_isDpiOpenArray = false;
|
m_isIfaceParent = false; m_isDpiOpenArray = false;
|
||||||
@ -1582,6 +1583,7 @@ public:
|
|||||||
void attrScBv(bool flag) { m_attrScBv = flag; }
|
void attrScBv(bool flag) { m_attrScBv = flag; }
|
||||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
||||||
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
||||||
|
void attrSplitVar(bool flag) { m_attrSplitVar = flag; }
|
||||||
void usedClock(bool flag) { m_usedClock = flag; }
|
void usedClock(bool flag) { m_usedClock = flag; }
|
||||||
void usedParam(bool flag) { m_usedParam = flag; }
|
void usedParam(bool flag) { m_usedParam = flag; }
|
||||||
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
|
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
|
||||||
@ -1658,6 +1660,7 @@ public:
|
|||||||
bool attrFileDescr() const { return m_fileDescr; }
|
bool attrFileDescr() const { return m_fileDescr; }
|
||||||
bool attrScClocked() const { return m_scClocked; }
|
bool attrScClocked() const { return m_scClocked; }
|
||||||
bool attrSFormat() const { return m_attrSFormat; }
|
bool attrSFormat() const { return m_attrSFormat; }
|
||||||
|
bool attrSplitVar() const { return m_attrSplitVar; }
|
||||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
||||||
VVarAttrClocker attrClocker() const { return m_attrClocker; }
|
VVarAttrClocker attrClocker() const { return m_attrClocker; }
|
||||||
virtual string verilogKwd() const;
|
virtual string verilogKwd() const;
|
||||||
|
@ -102,6 +102,7 @@ public:
|
|||||||
REDEFMACRO, // Redefining existing define macro
|
REDEFMACRO, // Redefining existing define macro
|
||||||
SELRANGE, // Selection index out of range
|
SELRANGE, // Selection index out of range
|
||||||
SHORTREAL, // Shortreal not supported
|
SHORTREAL, // Shortreal not supported
|
||||||
|
SPLITVAR, // Cannot split the variable
|
||||||
STMTDLY, // Delayed statement
|
STMTDLY, // Delayed statement
|
||||||
SYMRSVDWORD, // Symbol is Reserved Word
|
SYMRSVDWORD, // Symbol is Reserved Word
|
||||||
SYNCASYNCNET, // Mixed sync + async reset
|
SYNCASYNCNET, // Mixed sync + async reset
|
||||||
@ -153,7 +154,7 @@ public:
|
|||||||
"MULTIDRIVEN", "MULTITOP",
|
"MULTIDRIVEN", "MULTITOP",
|
||||||
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE",
|
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE",
|
||||||
"REALCVT", "REDEFMACRO",
|
"REALCVT", "REDEFMACRO",
|
||||||
"SELRANGE", "SHORTREAL", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
"SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||||
"TICKCOUNT",
|
"TICKCOUNT",
|
||||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
|
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
|
||||||
"UNPACKED", "UNSIGNED", "UNUSED",
|
"UNPACKED", "UNSIGNED", "UNUSED",
|
||||||
|
@ -2057,6 +2057,12 @@ private:
|
|||||||
AstVarXRef* refp = new AstVarXRef(nodep->fileline(), nodep->name(),
|
AstVarXRef* refp = new AstVarXRef(nodep->fileline(), nodep->name(),
|
||||||
m_ds.m_dotText, false); // lvalue'ness computed later
|
m_ds.m_dotText, false); // lvalue'ness computed later
|
||||||
refp->varp(varp);
|
refp->varp(varp);
|
||||||
|
if (varp->attrSplitVar()) {
|
||||||
|
refp->v3warn(SPLITVAR, varp->prettyNameQ()
|
||||||
|
<< " has split_var metacomment but will not be split because"
|
||||||
|
<< " it is accessed from another module via a dot.");
|
||||||
|
varp->attrSplitVar(false);
|
||||||
|
}
|
||||||
m_ds.m_dotText = "";
|
m_ds.m_dotText = "";
|
||||||
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
|
if (m_ds.m_unresolved && m_ds.m_unlinkedScope) {
|
||||||
string dotted = refp->dotted();
|
string dotted = refp->dotted();
|
||||||
|
@ -305,6 +305,16 @@ private:
|
|||||||
m_varp->attrSFormat(true);
|
m_varp->attrSFormat(true);
|
||||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||||
}
|
}
|
||||||
|
else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) {
|
||||||
|
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||||
|
if (!VN_IS(m_modp, Module)) {
|
||||||
|
m_varp->v3warn(SPLITVAR, m_varp->prettyNameQ() << " has split_var metacomment, "
|
||||||
|
"but will not be split because it is not declared in a module.");
|
||||||
|
} else {
|
||||||
|
m_varp->attrSplitVar(true);
|
||||||
|
}
|
||||||
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||||
|
}
|
||||||
else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
|
else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
|
||||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||||
m_varp->attrScBv(true);
|
m_varp->attrScBv(true);
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
#include "V3Partition.h"
|
#include "V3Partition.h"
|
||||||
#include "V3PartitionGraph.h"
|
#include "V3PartitionGraph.h"
|
||||||
#include "V3SenTree.h"
|
#include "V3SenTree.h"
|
||||||
|
#include "V3SplitVar.h"
|
||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
|
|
||||||
#include "V3Order.h"
|
#include "V3Order.h"
|
||||||
@ -892,32 +893,48 @@ private:
|
|||||||
m_graph.userClearVertices();
|
m_graph.userClearVertices();
|
||||||
// May be very large vector, so only report the "most important"
|
// May be very large vector, so only report the "most important"
|
||||||
// elements. Up to 10 of the widest
|
// elements. Up to 10 of the widest
|
||||||
std::cerr<<V3Error::msgPrefix()
|
std::cerr << V3Error::warnMore() << "... Widest candidate vars to split:" << endl;
|
||||||
<<" Widest candidate vars to split:"<<endl;
|
|
||||||
std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
|
std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
|
||||||
|
vl_unordered_set<const AstVar*> canSplitList;
|
||||||
int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
|
int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
|
||||||
for (int i = 0; i < lim; i++) {
|
for (int i = 0; i < lim; i++) {
|
||||||
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
|
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
|
||||||
AstVar* varp = vsvertexp->varScp()->varp();
|
AstVar* varp = vsvertexp->varScp()->varp();
|
||||||
std::cerr<<V3Error::msgPrefix()<<" "
|
const bool canSplit = V3SplitVar::canSplitVar(varp);
|
||||||
<<varp->fileline()<<" "<<varp->prettyName()<<std::dec
|
std::cerr << V3Error::warnMore() << " " << varp->fileline() << " "
|
||||||
<<", width "<<varp->width()<<", fanout "
|
<< varp->prettyName() << std::dec << ", width " << varp->width()
|
||||||
<<vsvertexp->fanout()<<endl;
|
<< ", fanout " << vsvertexp->fanout();
|
||||||
|
if (canSplit) {
|
||||||
|
std::cerr <<", can split_var";
|
||||||
|
canSplitList.insert(varp);
|
||||||
|
}
|
||||||
|
std::cerr << std::endl;
|
||||||
}
|
}
|
||||||
// Up to 10 of the most fanned out
|
// Up to 10 of the most fanned out
|
||||||
std::cerr<<V3Error::msgPrefix()
|
std::cerr << V3Error::warnMore()
|
||||||
<<" Most fanned out candidate vars to split:"<<endl;
|
<< "... Most fanned out candidate vars to split:" << endl;
|
||||||
std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(),
|
std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(),
|
||||||
OrderVarFanoutCmp());
|
OrderVarFanoutCmp());
|
||||||
lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
|
lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
|
||||||
for (int i = 0; i < lim; i++) {
|
for (int i = 0; i < lim; i++) {
|
||||||
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
|
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
|
||||||
AstVar* varp = vsvertexp->varScp()->varp();
|
AstVar* varp = vsvertexp->varScp()->varp();
|
||||||
std::cerr<<V3Error::msgPrefix()<<" "
|
const bool canSplit = V3SplitVar::canSplitVar(varp);
|
||||||
<<varp->fileline()<<" "<<varp->prettyName()
|
std::cerr << V3Error::warnMore() << " " << varp->fileline() << " "
|
||||||
<<", width "<<std::dec<<varp->width()
|
<< varp->prettyName() << ", width " << std::dec << varp->width()
|
||||||
<<", fanout "<<vsvertexp->fanout()<<endl;
|
<< ", fanout " << vsvertexp->fanout();
|
||||||
|
if (canSplit) {
|
||||||
|
std::cerr << ", can split_var";
|
||||||
|
canSplitList.insert(varp);
|
||||||
}
|
}
|
||||||
|
std::cerr<<endl;
|
||||||
|
}
|
||||||
|
if (!canSplitList.empty()) {
|
||||||
|
std::cerr << V3Error::warnMore()
|
||||||
|
<< "... Suggest add /*verilator split_var*/ to appropriate variables above."
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
V3Stats::addStat("Order, SplitVar, candidates", canSplitList.size());
|
||||||
m_unoptflatVars.clear();
|
m_unoptflatVars.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1310
src/V3SplitVar.cpp
Normal file
1310
src/V3SplitVar.cpp
Normal file
File diff suppressed because it is too large
Load Diff
39
src/V3SplitVar.h
Normal file
39
src/V3SplitVar.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Break variables into separate words to avoid UNOPTFLAT
|
||||||
|
//
|
||||||
|
// Code available from: https://verilator.org
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2020 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.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#ifndef _V3SPLITVAR_H_
|
||||||
|
#define _V3SPLITVAR_H_ 1
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
class AstNetlist;
|
||||||
|
class AstVar;
|
||||||
|
|
||||||
|
class V3SplitVar {
|
||||||
|
public:
|
||||||
|
// Split variables marked with split_var metacomment.
|
||||||
|
static void splitVariable(AstNetlist* nodep);
|
||||||
|
|
||||||
|
// Return true if the variable can be split.
|
||||||
|
// This check is not perfect.
|
||||||
|
static bool canSplitVar(const AstVar* varp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Guard
|
@ -82,6 +82,7 @@
|
|||||||
#include "V3Slice.h"
|
#include "V3Slice.h"
|
||||||
#include "V3Split.h"
|
#include "V3Split.h"
|
||||||
#include "V3SplitAs.h"
|
#include "V3SplitAs.h"
|
||||||
|
#include "V3SplitVar.h"
|
||||||
#include "V3Stats.h"
|
#include "V3Stats.h"
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
#include "V3Subst.h"
|
#include "V3Subst.h"
|
||||||
@ -175,12 +176,14 @@ static void process() {
|
|||||||
V3Const::constifyAllLint(v3Global.rootp());
|
V3Const::constifyAllLint(v3Global.rootp());
|
||||||
|
|
||||||
if (!v3Global.opt.xmlOnly()) {
|
if (!v3Global.opt.xmlOnly()) {
|
||||||
|
// Split packed variables into multiple pieces to resolve UNOPTFLAT.
|
||||||
|
// should be after constifyAllLint() which flattens to 1D bit vector
|
||||||
|
V3SplitVar::splitVariable(v3Global.rootp());
|
||||||
|
|
||||||
// Remove cell arrays (must be between V3Width and scoping)
|
// Remove cell arrays (must be between V3Width and scoping)
|
||||||
V3Inst::dearrayAll(v3Global.rootp());
|
V3Inst::dearrayAll(v3Global.rootp());
|
||||||
V3LinkDot::linkDotArrayed(v3Global.rootp());
|
V3LinkDot::linkDotArrayed(v3Global.rootp());
|
||||||
}
|
|
||||||
|
|
||||||
if (!v3Global.opt.xmlOnly()) {
|
|
||||||
// Task inlining & pushing BEGINs names to variables/cells
|
// Task inlining & pushing BEGINs names to variables/cells
|
||||||
// Begin processing must be after Param, before module inlining
|
// Begin processing must be after Param, before module inlining
|
||||||
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
|
||||||
|
@ -704,6 +704,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||||||
"/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; }
|
"/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; }
|
||||||
"/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc
|
"/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc
|
||||||
"/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; }
|
"/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; }
|
||||||
|
"/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; }
|
||||||
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
|
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
|
||||||
"/*verilator clocker*/" { FL; return yVL_CLOCKER; }
|
"/*verilator clocker*/" { FL; return yVL_CLOCKER; }
|
||||||
"/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; }
|
"/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; }
|
||||||
|
@ -639,6 +639,7 @@ class AstSenTree;
|
|||||||
%token<fl> yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/"
|
%token<fl> yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/"
|
||||||
%token<fl> yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/"
|
%token<fl> yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/"
|
||||||
%token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/"
|
%token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/"
|
||||||
|
%token<fl> yVL_SPLIT_VAR "/*verilator split_var*/"
|
||||||
|
|
||||||
%token<fl> yP_TICK "'"
|
%token<fl> yP_TICK "'"
|
||||||
%token<fl> yP_TICKBRA "'{"
|
%token<fl> yP_TICKBRA "'{"
|
||||||
@ -2282,6 +2283,7 @@ sigAttr<nodep>:
|
|||||||
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
|
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
|
||||||
| yVL_SC_BV { $$ = new AstAttrOf($1,AstAttrType::VAR_SC_BV); }
|
| yVL_SC_BV { $$ = new AstAttrOf($1,AstAttrType::VAR_SC_BV); }
|
||||||
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
|
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
|
||||||
|
| yVL_SPLIT_VAR { $$ = new AstAttrOf($1,AstAttrType::VAR_SPLIT_VAR); }
|
||||||
;
|
;
|
||||||
|
|
||||||
rangeListE<rangep>: // IEEE: [{packed_dimension}]
|
rangeListE<rangep>: // IEEE: [{packed_dimension}]
|
||||||
|
26
test_regress/t/t_split_var_0.pl
Executable file
26
test_regress/t/t_split_var_0.pl
Executable file
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/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.
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning.
|
||||||
|
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||||
|
# So use 6 threads here though it's not optimal in performace wise, but ok.
|
||||||
|
compile(
|
||||||
|
verilator_flags2 => ['--stats' . ($Self->{vltmt} ? ' --threads 6' : '')],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
file_grep($Self->{stats}, qr/SplitVar,\s+Split packed variables\s+(\d+)/i, 13);
|
||||||
|
file_grep($Self->{stats}, qr/SplitVar,\s+Split unpacked arrays\s+(\d+)/i, 23);
|
||||||
|
ok(1);
|
||||||
|
1;
|
431
test_regress/t/t_split_var_0.v
Normal file
431
test_regress/t/t_split_var_0.v
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2020 by Yutetsu TAKATSUKASA.
|
||||||
|
|
||||||
|
// If split_var pragma is removed, UNOPTFLAT appears.
|
||||||
|
|
||||||
|
module barshift_1d_unpacked #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out /*verilator split_var*/);
|
||||||
|
|
||||||
|
localparam OFFSET = -3;
|
||||||
|
logic [WIDTH-1:0] tmp[DEPTH+OFFSET:OFFSET] /*verilator split_var*/;
|
||||||
|
generate
|
||||||
|
for(genvar i = 0; i < DEPTH; ++i) begin
|
||||||
|
always_comb
|
||||||
|
if (shift[i]) begin
|
||||||
|
/*verilator lint_off ALWCOMBORDER*/
|
||||||
|
tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]};
|
||||||
|
/*verilator lint_on ALWCOMBORDER*/
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
tmp[i+1+OFFSET] = tmp[i+OFFSET];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign tmp[0+OFFSET] = in;
|
||||||
|
assign out[WIDTH-1-:WIDTH-1] = tmp[DEPTH+OFFSET][WIDTH-1:1];
|
||||||
|
assign out[0] = tmp[DEPTH+OFFSET][0+:1];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module barshift_1d_unpacked_le #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
localparam OFFSET = -3;
|
||||||
|
// almost same as above module, but tmp[smaller:bigger] here.
|
||||||
|
logic [WIDTH-1:0] tmp[OFFSET:DEPTH+OFFSET] /*verilator split_var*/;
|
||||||
|
generate
|
||||||
|
for(genvar i = 0; i < DEPTH; ++i) begin
|
||||||
|
always_comb
|
||||||
|
if (shift[i]) begin
|
||||||
|
/*verilator lint_off ALWCOMBORDER*/
|
||||||
|
tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]};
|
||||||
|
/*verilator lint_on ALWCOMBORDER*/
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
tmp[i+1+OFFSET] = tmp[i+OFFSET];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign tmp[0+OFFSET] = in;
|
||||||
|
assign out = tmp[DEPTH+OFFSET];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module barshift_1d_unpacked_struct0 #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
localparam OFFSET = 1;
|
||||||
|
typedef struct packed { logic [WIDTH-1:0] data; } data_type;
|
||||||
|
data_type tmp[DEPTH+OFFSET:OFFSET] /*verilator split_var*/;
|
||||||
|
generate
|
||||||
|
for(genvar i = 0; i < DEPTH; ++i) begin
|
||||||
|
always_comb
|
||||||
|
if (shift[i]) begin
|
||||||
|
/*verilator lint_off ALWCOMBORDER*/
|
||||||
|
tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]};
|
||||||
|
/*verilator lint_on ALWCOMBORDER*/
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
tmp[i+1+OFFSET] = tmp[i+OFFSET];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign tmp[0+OFFSET] = in;
|
||||||
|
assign out = tmp[DEPTH+OFFSET];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module barshift_2d_unpacked #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
localparam OFFSET = 1;
|
||||||
|
localparam N = 3;
|
||||||
|
reg [WIDTH-1:0] tmp0[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
reg [WIDTH-1:0] tmp1[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
reg [WIDTH-1:0] tmp2[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1];
|
||||||
|
reg [WIDTH-1:0] tmp3[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
reg [WIDTH-1:0] tmp4[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
reg [WIDTH-1:0] tmp5[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1];
|
||||||
|
reg [WIDTH-1:0] tmp6[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
|
||||||
|
reg [WIDTH-1:0] tmp7[DEPTH+OFFSET+1:OFFSET+1][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
reg [WIDTH-1:0] tmp8[DEPTH+OFFSET+3:OFFSET-1][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
reg [WIDTH-1:0] tmp9[DEPTH+OFFSET+3:OFFSET+3][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
reg [WIDTH-1:0] tmp10[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
// because tmp11 is not split for testing mixture usage of split_var and no-spliv_ar,
|
||||||
|
// UNOPTFLAT appears, but it's fine.
|
||||||
|
/*verilator lint_off UNOPTFLAT*/
|
||||||
|
reg [WIDTH-1:0] tmp11[-1:1][DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1];
|
||||||
|
/*verilator lint_on UNOPTFLAT*/
|
||||||
|
reg [WIDTH-1:0] tmp12[-1:0][DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
reg [WIDTH-1:0] tmp13[DEPTH+OFFSET:OFFSET][OFFSET:OFFSET+N-1] /*verilator split_var*/;
|
||||||
|
|
||||||
|
generate
|
||||||
|
for(genvar i = 0; i < DEPTH; ++i) begin
|
||||||
|
for(genvar j = OFFSET; j < N + OFFSET; ++j) begin
|
||||||
|
always_comb
|
||||||
|
if (shift[i]) begin
|
||||||
|
/*verilator lint_off ALWCOMBORDER*/
|
||||||
|
tmp0[i+1+OFFSET][j] = {tmp0[i+OFFSET][j][(1 << i)-1:0], tmp0[i+OFFSET][j][WIDTH-1:(2**i)]};
|
||||||
|
/*verilator lint_on ALWCOMBORDER*/
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
tmp0[i+1+OFFSET][j] = tmp0[i+OFFSET][j];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for(genvar j = OFFSET; j < N + OFFSET; ++j) begin
|
||||||
|
assign tmp0[0 + OFFSET][j] = in;
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign tmp1 = tmp0; // split both side
|
||||||
|
assign tmp2 = tmp1; // split only rhs
|
||||||
|
assign tmp3 = tmp2; // split only lhs
|
||||||
|
always_comb tmp4 = tmp3; // split both side
|
||||||
|
always_comb tmp5 = tmp4; // split only rhs
|
||||||
|
always_comb tmp6 = tmp5; // split only lhs
|
||||||
|
|
||||||
|
assign tmp7 = tmp6;
|
||||||
|
assign tmp8[DEPTH+OFFSET+1:OFFSET+1] = tmp7;
|
||||||
|
assign tmp9 = tmp8[DEPTH+OFFSET+1:OFFSET+1];
|
||||||
|
assign tmp10[DEPTH+OFFSET:OFFSET] = tmp9[DEPTH+OFFSET+3:OFFSET+3];
|
||||||
|
assign tmp11[1] = tmp10;
|
||||||
|
assign tmp11[-1] = tmp11[1];
|
||||||
|
assign tmp11[0] = tmp11[-1];
|
||||||
|
assign tmp12 = tmp11[0:1];
|
||||||
|
assign out = tmp12[1][DEPTH+OFFSET][OFFSET];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module barshift_1d_unpacked_struct1 #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
localparam OFFSET = 2;
|
||||||
|
typedef struct packed { int data; } data_type;
|
||||||
|
data_type tmp[DEPTH+OFFSET:OFFSET] /*verilator split_var*/;
|
||||||
|
|
||||||
|
localparam [32-WIDTH-1:0] pad = 0;
|
||||||
|
generate
|
||||||
|
for(genvar i = 0; i < DEPTH; ++i) begin
|
||||||
|
always_comb
|
||||||
|
if (shift[i]) begin
|
||||||
|
/*verilator lint_off ALWCOMBORDER*/
|
||||||
|
tmp[i+1+OFFSET] = {pad, tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]};
|
||||||
|
/*verilator lint_on ALWCOMBORDER*/
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
tmp[i+1+OFFSET] = tmp[i+OFFSET];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign tmp[0+OFFSET] = {pad, in};
|
||||||
|
assign out = tmp[DEPTH+OFFSET][WIDTH-1:0];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module barshift_2d_packed_array #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
localparam OFFSET = -2;
|
||||||
|
/*verilator lint_off LITENDIAN*/
|
||||||
|
reg [OFFSET:DEPTH+OFFSET][WIDTH-1:0] tmp /*verilator split_var*/;
|
||||||
|
/*verilator lint_on LITENDIAN*/
|
||||||
|
|
||||||
|
generate
|
||||||
|
for(genvar i = 0; i < DEPTH; ++i) begin
|
||||||
|
always_comb
|
||||||
|
/*verilator lint_off ALWCOMBORDER*/
|
||||||
|
if (shift[i]) begin
|
||||||
|
tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]};
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
tmp[i+1+OFFSET][1:0] = tmp[i+OFFSET][1:0];
|
||||||
|
tmp[i+1+OFFSET][WIDTH-1:2] = tmp[i+OFFSET][WIDTH-1:2];
|
||||||
|
end
|
||||||
|
/*verilator lint_on ALWCOMBORDER*/
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign tmp[0+OFFSET] = in;
|
||||||
|
assign out = tmp[DEPTH+OFFSET];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module barshift_2d_packed_array_le #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
localparam OFFSET = -2;
|
||||||
|
/*verilator lint_off LITENDIAN*/
|
||||||
|
reg [OFFSET:DEPTH+OFFSET][OFFSET:WIDTH-1+OFFSET] tmp /*verilator split_var*/;
|
||||||
|
/*verilator lint_on LITENDIAN*/
|
||||||
|
|
||||||
|
generate
|
||||||
|
for(genvar i = 0; i < DEPTH; ++i) begin
|
||||||
|
always_comb
|
||||||
|
/*verilator lint_off ALWCOMBORDER*/
|
||||||
|
if (shift[i]) begin
|
||||||
|
tmp[i+1+OFFSET] = {tmp[i+OFFSET][WIDTH-(2**i)+OFFSET:WIDTH-1+OFFSET], tmp[i+OFFSET][OFFSET:WIDTH-(2**i)-1+OFFSET]};
|
||||||
|
end
|
||||||
|
else begin // actulally just tmp[i+1+OFFSET] = tmp[i+OFFSET]
|
||||||
|
tmp[i+1+OFFSET][0+OFFSET:2+OFFSET] = tmp[i+OFFSET][0+OFFSET:2+OFFSET];
|
||||||
|
tmp[i+1+OFFSET][3+OFFSET] = tmp[i+OFFSET][3+OFFSET];
|
||||||
|
{tmp[i+1+OFFSET][4+OFFSET],tmp[i+1+OFFSET][5+OFFSET]} = {tmp[i+OFFSET][4+OFFSET], tmp[i+OFFSET][5+OFFSET]};
|
||||||
|
{tmp[i+1+OFFSET][7+OFFSET],tmp[i+1+OFFSET][6+OFFSET]} = {tmp[i+OFFSET][7+OFFSET], tmp[i+OFFSET][6+OFFSET]};
|
||||||
|
end
|
||||||
|
/*verilator lint_on ALWCOMBORDER*/
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign tmp[0+OFFSET] = in;
|
||||||
|
assign out = tmp[DEPTH+OFFSET];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module barshift_1d_packed_struct #(localparam DEPTH = 3, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
logic [WIDTH-1:0] v0, v1, v2, v3;
|
||||||
|
} data_type;
|
||||||
|
wire data_type tmp /*verilator split_var*/;
|
||||||
|
|
||||||
|
assign tmp.v0 = in;
|
||||||
|
assign tmp.v1 = shift[0] == 1'b1 ? {tmp.v0[(1 << 0)-1:0], tmp.v0[WIDTH-1:2**0]} : tmp.v0;
|
||||||
|
assign tmp.v2 = shift[1] == 1'b1 ? {tmp.v1[(1 << 1)-1:0], tmp.v1[WIDTH-1:2**1]} : tmp.v1;
|
||||||
|
assign tmp.v3 = shift[2] == 1'b1 ? {tmp.v2[(1 << 2)-1:0], tmp.v2[WIDTH-1:2**2]} : tmp.v2;
|
||||||
|
assign out = tmp.v3;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module barshift_bitslice #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH)
|
||||||
|
(input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
/*verilator lint_off LITENDIAN*/
|
||||||
|
wire [0:WIDTH*(DEPTH+1) - 1] tmp /*verilator split_var*/;
|
||||||
|
/*verilator lint_on LITENDIAN*/
|
||||||
|
|
||||||
|
generate
|
||||||
|
for(genvar i = 0; i < DEPTH; ++i) begin
|
||||||
|
always_comb
|
||||||
|
if (shift[i]) begin
|
||||||
|
tmp[WIDTH*(i+1):WIDTH*(i+1+1)-1] = {tmp[WIDTH*(i+1)-(1<<i):WIDTH*(i+1)-1], tmp[WIDTH*i:WIDTH*i+((WIDTH-1) - (2**i))]};
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
tmp[WIDTH*(i+1):WIDTH*(i+1+1)-1] = tmp[WIDTH*i:WIDTH*(i+1)-1];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
assign tmp[WIDTH*0:WIDTH*(0+1)-1] = in;
|
||||||
|
assign out = tmp[WIDTH*DEPTH:WIDTH*(DEPTH+1)-1];
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module var_decl_with_init();
|
||||||
|
|
||||||
|
/*verilator lint_off LITENDIAN*/
|
||||||
|
logic [-1:30] var0 /* verilator split_var */ = {4'd0, 4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7};
|
||||||
|
logic [-1:30] var2 /* verilator split_var */;
|
||||||
|
/*verilator lint_on LITENDIAN*/
|
||||||
|
logic [30:-1] var1 /* verilator split_var */ = {4'd0, 4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7};
|
||||||
|
logic [30:-1] var3 /* verilator split_var */;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
var2[-1:2] = 4'd2;
|
||||||
|
var3[2:-1] = 4'd3;
|
||||||
|
$display("%x %x", var0, var1);
|
||||||
|
$display("%x %x", var2, var3);
|
||||||
|
var0[-1:5] = 7'd0;
|
||||||
|
var1[10:3] = 8'd2;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module t_array_rev(clk); // from t_array_rev.v
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
// verilator lint_off LITENDIAN
|
||||||
|
logic arrd [0:1] /*verilator split_var*/ = '{ 1'b1, 1'b0 };
|
||||||
|
// verilator lint_on LITENDIAN
|
||||||
|
logic y0, y1;
|
||||||
|
logic localbkw [1:0]/*verilator split_var*/ ;
|
||||||
|
|
||||||
|
arr_rev arr_rev_u
|
||||||
|
(
|
||||||
|
.arrbkw (arrd),
|
||||||
|
.y0(y0),
|
||||||
|
.y1(y1)
|
||||||
|
);
|
||||||
|
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
if (arrd[0] != 1'b1) $stop;
|
||||||
|
if (arrd[1] != 1'b0) $stop;
|
||||||
|
|
||||||
|
localbkw = arrd;
|
||||||
|
if (localbkw[0] != 1'b0) $stop;
|
||||||
|
if (localbkw[1] != 1'b1) $stop;
|
||||||
|
|
||||||
|
if (y0 != 1'b0) $stop;
|
||||||
|
if (y1 != 1'b1) $stop;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module arr_rev
|
||||||
|
(
|
||||||
|
input var logic arrbkw [1:0]/*verilator split_var*/ ,
|
||||||
|
output var logic y0,
|
||||||
|
output var logic y1
|
||||||
|
);
|
||||||
|
|
||||||
|
always_comb y0 = arrbkw[0];
|
||||||
|
always_comb y1 = arrbkw[1];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module pack2unpack #(parameter WIDTH = 8)
|
||||||
|
(input wire [WIDTH-1:0] in/*verilator split_var*/, output wire out [WIDTH-1:0] /*verilator split_var*/);
|
||||||
|
|
||||||
|
generate
|
||||||
|
for (genvar i = 0; i < WIDTH; ++i) begin
|
||||||
|
assign out[i] = in[i];
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module unpack2pack #(parameter WIDTH = 8)
|
||||||
|
(input wire in [WIDTH-1:0] /*verilator split_var*/, output wire [WIDTH-1:0] out/*verilator split_var*/);
|
||||||
|
|
||||||
|
function automatic [1:0] to_packed0;
|
||||||
|
logic [1:0] tmp /*verilator split_var*/;
|
||||||
|
input logic in[1:0] /*verilator split_var*/;
|
||||||
|
tmp[1] = in[1];
|
||||||
|
tmp[0] = in[0];
|
||||||
|
return tmp;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
/* verilator lint_off UNOPTFLAT*/
|
||||||
|
task automatic to_packed1(input logic in[1:0] /*verilator split_var*/, output logic [1:0] out /*verilator split_var*/);
|
||||||
|
out[1] = in[1];
|
||||||
|
out[0] = in[0];
|
||||||
|
endtask
|
||||||
|
/* verilator lint_on UNOPTFLAT*/
|
||||||
|
|
||||||
|
|
||||||
|
generate
|
||||||
|
for (genvar i = 4; i < WIDTH; i += 4) begin
|
||||||
|
always @(*) begin
|
||||||
|
out[i+1:i] = to_packed0(in[i+1:i]);
|
||||||
|
out[i+3:i+2] = to_packed0(in[i+3:i+2]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
always_comb
|
||||||
|
to_packed1(.in(in[1:0]), .out(out[1:0]));
|
||||||
|
always_comb
|
||||||
|
to_packed1(.in(in[3:2]), .out(out[3:2]));
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module through #(parameter WIDTH = 8)
|
||||||
|
(input wire [WIDTH-1:0] in, output wire [WIDTH-1:0] out);
|
||||||
|
|
||||||
|
logic unpack_tmp [0:WIDTH-1] /*verilator split_var*/;
|
||||||
|
pack2unpack i_pack2unpack(.in(in), .out(unpack_tmp));
|
||||||
|
unpack2pack i_unpack2pack(.in(unpack_tmp), .out(out));
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/ clk);
|
||||||
|
input clk;
|
||||||
|
localparam DEPTH = 3;
|
||||||
|
localparam WIDTH = 2**DEPTH;
|
||||||
|
localparam NUMSUB = 9;
|
||||||
|
|
||||||
|
logic [WIDTH-1:0] in;
|
||||||
|
logic [WIDTH-1:0] out[0:NUMSUB-1];
|
||||||
|
logic [WIDTH-1:0] through_tmp;
|
||||||
|
logic [DEPTH-1:0] shift = 0;
|
||||||
|
|
||||||
|
// barrel shifter
|
||||||
|
barshift_1d_unpacked #(.DEPTH(DEPTH)) shifter0(.in(in), .out(out[0]), .shift(shift));
|
||||||
|
barshift_1d_unpacked_le #(.DEPTH(DEPTH)) shifter1(.in(in), .out(out[1]), .shift(shift));
|
||||||
|
barshift_1d_unpacked_struct0 #(.DEPTH(DEPTH)) shifter2(.in(in), .out(out[2]), .shift(shift));
|
||||||
|
barshift_2d_unpacked #(.DEPTH(DEPTH)) shifter3(.in(in), .out(out[3]), .shift(shift));
|
||||||
|
barshift_1d_unpacked_struct1 #(.DEPTH(DEPTH)) shifter4(.in(in), .out(out[4]), .shift(shift));
|
||||||
|
barshift_2d_packed_array #(.DEPTH(DEPTH)) shifter5(.in(in), .out(out[5]), .shift(shift));
|
||||||
|
barshift_2d_packed_array_le #(.DEPTH(DEPTH)) shifter6(.in(in), .out(out[6]), .shift(shift));
|
||||||
|
barshift_1d_packed_struct shifter7(.in(in), .out(out[7]), .shift(shift));
|
||||||
|
barshift_bitslice #(.DEPTH(DEPTH)) shifter8(.in(in), .out(out[8]), .shift(shift));
|
||||||
|
through #(.WIDTH(WIDTH)) though0 (.in(out[8]), .out(through_tmp));
|
||||||
|
var_decl_with_init i_var_decl_with_init();
|
||||||
|
t_array_rev i_t_array_rev(clk);
|
||||||
|
|
||||||
|
assign in = 8'b10001110;
|
||||||
|
/*verilator lint_off LITENDIAN*/
|
||||||
|
logic [7:0] [7:0] expc
|
||||||
|
= {8'b10001110, 8'b01000111, 8'b10100011, 8'b11010001,
|
||||||
|
8'b11101000, 8'b01110100, 8'b00111010, 8'b00011101};
|
||||||
|
/*verilator lint_on LITENDIAN*/
|
||||||
|
always @(posedge clk) begin : always_block
|
||||||
|
automatic bit failed = 0;
|
||||||
|
$display("in:%b shift:%d expc:%b", in, shift, expc[7-shift]);
|
||||||
|
for (int i = 0; i < NUMSUB; ++i) begin
|
||||||
|
if (out[i] != expc[7-shift]) begin
|
||||||
|
$display("Missmatch out[%d]:%b", i, out[i]);
|
||||||
|
failed = 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (through_tmp != expc[7-shift]) begin
|
||||||
|
$display("Missmatch through_tmp:%b", through_tmp);
|
||||||
|
failed = 1;
|
||||||
|
end
|
||||||
|
if (failed) $stop;
|
||||||
|
if (shift == 7) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
shift <= shift + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
65
test_regress/t/t_split_var_1_bad.out
Normal file
65
test_regress/t/t_split_var_1_bad.out
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:6: 'should_show_warning_global0' has split_var metacomment, but will not be split because it is not declared in a module.
|
||||||
|
logic [7:0] should_show_warning_global0 /*verilator split_var*/ ;
|
||||||
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
... Use "/* verilator lint_off SPLITVAR */" and lint_on around source to disable this message.
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:7: 'should_show_warning_global1' has split_var metacomment, but will not be split because it is not declared in a module.
|
||||||
|
logic [7:0] should_show_warning_global1 [1:0] /*verilator split_var*/ ;
|
||||||
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:10: 'should_show_warning_ifs0' has split_var metacomment, but will not be split because it is not declared in a module.
|
||||||
|
logic [7:0] should_show_warning_ifs0 /*verilator split_var*/ ;
|
||||||
|
^~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:11: 'should_show_warning_ifs1' has split_var metacomment, but will not be split because it is not declared in a module.
|
||||||
|
logic [7:0] should_show_warning_ifs1 [1:0] /*verilator split_var*/ ;
|
||||||
|
^~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:37: 'cannot_split1' has split_var metacomment but will not be split because it is accessed from another module via a dot.
|
||||||
|
i_sub0.cannot_split1[0] = 0;
|
||||||
|
^~~~~~~~~~~~~
|
||||||
|
%Warning-SELRANGE: t/t_split_var_1_bad.v:82: Selection index out of range: 13 outside 12:10
|
||||||
|
: ... In instance t.i_sub3
|
||||||
|
assign outwires[12] = inwires[13];
|
||||||
|
^
|
||||||
|
%Warning-WIDTH: t/t_split_var_1_bad.v:38: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's FUNCREF 'bad_func' generates 32 bits.
|
||||||
|
: ... In instance t
|
||||||
|
i_sub0.cannot_split1[1] = bad_func(addr, rd_data0);
|
||||||
|
^
|
||||||
|
%Error: t/t_split_var_1_bad.v:71: Illegal assignment of constant to unpacked array
|
||||||
|
: ... In instance t.i_sub2
|
||||||
|
assign b = a[0];
|
||||||
|
^
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:50: 'cannot_split0' has split_var metacomment but will not be split because index cannot be determined statically.
|
||||||
|
: ... In instance t.i_sub0
|
||||||
|
rd_data = cannot_split0[addr];
|
||||||
|
^~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:82: 'inwires' has split_var metacomment but will not be split because index is out of range.
|
||||||
|
: ... In instance t.i_sub3
|
||||||
|
assign outwires[12] = inwires[13];
|
||||||
|
^~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:16: 'should_show_warning0' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic
|
||||||
|
: ... In instance t
|
||||||
|
real should_show_warning0 /*verilator split_var*/ ;
|
||||||
|
^~~~~~~~~~~~~~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:17: 'should_show_warning1' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic
|
||||||
|
: ... In instance t
|
||||||
|
string should_show_warning1 /*verilator split_var*/ ;
|
||||||
|
^~~~~~~~~~~~~~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:18: 'should_show_warning2' has split_var metacomment but will not be split because its bitwidth is 1
|
||||||
|
: ... In instance t
|
||||||
|
wire should_show_warning2 /*verilator split_var*/ ;
|
||||||
|
^~~~~~~~~~~~~~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:29: 'inout_port' has split_var metacomment but will not be split because it is an inout port
|
||||||
|
: ... In instance t
|
||||||
|
function int bad_func(inout logic [3:0] inout_port /*verilator split_var*/ ,
|
||||||
|
^~~~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:30: 'ref_port' has split_var metacomment but will not be split because it is a ref argument
|
||||||
|
: ... In instance t
|
||||||
|
ref logic [7:0] ref_port /*verilator split_var*/ );
|
||||||
|
^~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:56: 'cannot_split_genvar' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic
|
||||||
|
: ... In instance t.i_sub1
|
||||||
|
genvar cannot_split_genvar /*verilator split_var*/ ;
|
||||||
|
^~~~~~~~~~~~~~~~~~~
|
||||||
|
%Warning-SPLITVAR: t/t_split_var_1_bad.v:59: 'cannot_split' has split_var metacomment but will not be split because its bit range cannot be determined statically.
|
||||||
|
: ... In instance t.i_sub1
|
||||||
|
rd_data = cannot_split[addr];
|
||||||
|
^
|
||||||
|
%Error: Exiting due to
|
19
test_regress/t/t_split_var_1_bad.pl
Executable file
19
test_regress/t/t_split_var_1_bad.pl
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/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.
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
fails => 1,
|
||||||
|
verilator_flags2 => ['--stats'],
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
84
test_regress/t/t_split_var_1_bad.v
Normal file
84
test_regress/t/t_split_var_1_bad.v
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2020 by Yutetsu TAKATSUKASA.
|
||||||
|
|
||||||
|
logic [7:0] should_show_warning_global0 /* verilator split_var */;
|
||||||
|
logic [7:0] should_show_warning_global1 [1:0] /* verilator split_var */;
|
||||||
|
|
||||||
|
interface ifs;
|
||||||
|
logic [7:0] should_show_warning_ifs0 /* verilator split_var */;
|
||||||
|
logic [7:0] should_show_warning_ifs1 [1:0] /* verilator split_var */;
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
module t();
|
||||||
|
// The following variables can not be splitted. will see warnings.
|
||||||
|
real should_show_warning0 /*verilator split_var*/;
|
||||||
|
string should_show_warning1 /*verilator split_var*/;
|
||||||
|
wire should_show_warning2 /*verilator split_var*/;
|
||||||
|
|
||||||
|
logic [3:0] addr;
|
||||||
|
logic [7:0] rd_data0, rd_data1, rd_data2;
|
||||||
|
|
||||||
|
sub0 i_sub0(.addr(addr), .rd_data(rd_data0));
|
||||||
|
sub1 i_sub1(.addr(addr), .rd_data(rd_data2));
|
||||||
|
sub2 i_sub2;
|
||||||
|
sub3 i_sub3;
|
||||||
|
ifs i_ifs();
|
||||||
|
|
||||||
|
function int bad_func(inout logic [3:0] inout_port /*verilator split_var*/,
|
||||||
|
ref logic [7:0] ref_port /*verilator split_var*/);
|
||||||
|
return 0;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
addr = 0;
|
||||||
|
addr = 1;
|
||||||
|
i_sub0.cannot_split1[0] = 0;
|
||||||
|
i_sub0.cannot_split1[1] = bad_func(addr, rd_data0);
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module sub0(input [3:0]addr, output logic [7:0] rd_data);
|
||||||
|
|
||||||
|
logic [7:0] cannot_split0[0:15] /*verilator split_var*/;
|
||||||
|
logic [7:0] cannot_split1[0:15] /*verilator split_var*/;
|
||||||
|
always_comb
|
||||||
|
rd_data = cannot_split0[addr];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module sub1(input [3:0]addr, output logic [7:0] rd_data);
|
||||||
|
genvar cannot_split_genvar /*verilator split_var*/;
|
||||||
|
logic [15:0] [7:0] cannot_split /*verilator split_var*/;
|
||||||
|
always_comb
|
||||||
|
rd_data = cannot_split[addr];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
|
module sub2; // from t_bitsel_wire_array_bad.v
|
||||||
|
|
||||||
|
// a and b are arrays of length 1.
|
||||||
|
wire a[0:0] /* verilator split_var */ ; // Array of nets
|
||||||
|
wire b[0:0] /* verilator split_var */ ;
|
||||||
|
|
||||||
|
assign a = 1'b0; // Only net assignment allowed
|
||||||
|
assign b = a[0]; // Only net assignment allowed
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sub3; // from t_select_bad_range3.v
|
||||||
|
|
||||||
|
logic [7:0] inwires [12:10] /* verilator split_var */;
|
||||||
|
wire [7:0] outwires [12:10] /* verilator split_var */;
|
||||||
|
|
||||||
|
assign outwires[10] = inwires[11];
|
||||||
|
assign outwires[11] = inwires[12];
|
||||||
|
assign outwires[12] = inwires[13]; // must be an error here
|
||||||
|
|
||||||
|
endmodule
|
1930
test_regress/t/t_split_var_2_trace.out
Normal file
1930
test_regress/t/t_split_var_2_trace.out
Normal file
File diff suppressed because it is too large
Load Diff
29
test_regress/t/t_split_var_2_trace.pl
Executable file
29
test_regress/t/t_split_var_2_trace.pl
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/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.
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
top_filename("t/t_split_var_0.v");
|
||||||
|
|
||||||
|
# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning.
|
||||||
|
# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads.
|
||||||
|
# So use 6 threads here though it's not optimal in performace wise, but ok.
|
||||||
|
compile(
|
||||||
|
verilator_flags2 => ['--cc --trace --stats' . ($Self->{vltmt} ? ' --threads 6' : '')],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename});
|
||||||
|
file_grep($Self->{stats}, qr/SplitVar,\s+Split packed variables\s+(\d+)/i, 12);
|
||||||
|
file_grep($Self->{stats}, qr/SplitVar,\s+Split unpacked arrays\s+(\d+)/i, 23);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
@ -5,8 +5,9 @@
|
|||||||
t/t_unoptflat_simple_2.v:14: Example path: t.x
|
t/t_unoptflat_simple_2.v:14: Example path: t.x
|
||||||
t/t_unoptflat_simple_2.v:16: Example path: ASSIGNW
|
t/t_unoptflat_simple_2.v:16: Example path: ASSIGNW
|
||||||
t/t_unoptflat_simple_2.v:14: Example path: t.x
|
t/t_unoptflat_simple_2.v:14: Example path: t.x
|
||||||
%Warning-UNOPTFLAT: Widest candidate vars to split:
|
... Widest candidate vars to split:
|
||||||
%Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 10
|
t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 10, can split_var
|
||||||
%Warning-UNOPTFLAT: Most fanned out candidate vars to split:
|
... Most fanned out candidate vars to split:
|
||||||
%Warning-UNOPTFLAT: t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 10
|
t/t_unoptflat_simple_2.v:14: t.x, width 3, fanout 10, can split_var
|
||||||
|
... Suggest add /*verilator split_var*/ to appropriate variables above.
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
Loading…
Reference in New Issue
Block a user