mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Merge branch 'master' into develop-v5
This commit is contained in:
commit
c6bce636ee
10
.github/workflows/format.yml
vendored
10
.github/workflows/format.yml
vendored
@ -10,11 +10,11 @@ on:
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-20.04
|
||||
name: Ubuntu 20.04 | format
|
||||
runs-on: ubuntu-22.04
|
||||
name: Ubuntu 22.04 | format
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
CI_RUNS_ON: ubuntu-20.04
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
CI_COMMIT: ${{ github.sha }}
|
||||
CI_M32: 0
|
||||
steps:
|
||||
@ -27,14 +27,14 @@ jobs:
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
run: |
|
||||
bash ci/ci-install.bash &&
|
||||
sudo apt-get install clang-format-11 yapf3 &&
|
||||
sudo apt-get install clang-format-14 yapf3 &&
|
||||
git config --global user.email "action@example.com" &&
|
||||
git config --global user.name "github action"
|
||||
- name: Format code
|
||||
run: |
|
||||
autoconf &&
|
||||
./configure &&
|
||||
make -j 2 format CLANGFORMAT=clang-format-11 &&
|
||||
make -j 2 format CLANGFORMAT=clang-format-14 &&
|
||||
git status
|
||||
- name: Push
|
||||
run: |
|
||||
|
@ -346,13 +346,13 @@ analyzer-include:
|
||||
|
||||
format: clang-format yapf format-pl-exec
|
||||
|
||||
CLANGFORMAT = clang-format-11
|
||||
CLANGFORMAT = clang-format-14
|
||||
CLANGFORMAT_FLAGS = -i
|
||||
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* test_regress/t/*.h
|
||||
|
||||
clang-format:
|
||||
@$(CLANGFORMAT) --version | egrep 11.0 > /dev/null \
|
||||
|| echo "*** You are not using clang-format 11.0, indents may differ from master's ***"
|
||||
@$(CLANGFORMAT) --version | egrep 14.0 > /dev/null \
|
||||
|| echo "*** You are not using clang-format-14, indents may differ from master's ***"
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
||||
|
||||
PY_PROGRAMS = \
|
||||
|
@ -44,6 +44,7 @@ HyungKi Jeong
|
||||
Iru Cai
|
||||
Ivan Vnučec
|
||||
Iztok Jeras
|
||||
Jake Merdich
|
||||
James Hanlon
|
||||
James Hutchinson
|
||||
James Pallister
|
||||
|
@ -13,6 +13,7 @@ from datetime import datetime
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('./_ext'))
|
||||
|
||||
import sphinx_rtd_theme # pylint: disable=wrong-import-position,
|
||||
|
@ -124,7 +124,7 @@ Those developing Verilator itself may also want these (see internals.rst):
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install gdb graphviz cmake clang clang-format-11 gprof lcov
|
||||
sudo apt-get install gdb graphviz cmake clang clang-format-14 gprof lcov
|
||||
sudo apt-get install yapf3
|
||||
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe
|
||||
cpan install Pod::Perldoc
|
||||
|
@ -16,12 +16,13 @@ from shutil import copy2
|
||||
|
||||
|
||||
class VlFileCopy:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
verilator_args, # presently all verilator options are passed-thru
|
||||
# ideally this script would check against options mentioned in help
|
||||
self,
|
||||
verilator_args, # presently all verilator options are passed-thru
|
||||
# ideally this script would check against options mentioned in help
|
||||
debug=0,
|
||||
output_dir='copied'): # directory name we output file uses
|
||||
output_dir='copied'): # directory name we output file uses
|
||||
|
||||
self.debug = debug
|
||||
|
||||
|
@ -14,12 +14,13 @@ import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
class VlHierGraph:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
verilator_args, # presently all verilator options are passed-thru
|
||||
# ideally this script would check against options mentioned in help
|
||||
self,
|
||||
verilator_args, # presently all verilator options are passed-thru
|
||||
# ideally this script would check against options mentioned in help
|
||||
debug=0,
|
||||
output_filename='graph.dot'): # output filename
|
||||
output_filename='graph.dot'): # output filename
|
||||
self.debug = debug
|
||||
self.next_vertex_number = 0
|
||||
self.name_to_number = {}
|
||||
|
@ -96,7 +96,7 @@ public:
|
||||
*(reinterpret_cast<uint32_t*>(newp)) = activeMagic();
|
||||
return newp + 8;
|
||||
}
|
||||
static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE {
|
||||
static void operator delete(void* obj, size_t /*size*/) VL_MT_SAFE {
|
||||
uint8_t* const oldp = (static_cast<uint8_t*>(obj)) - 8;
|
||||
if (VL_UNLIKELY(*(reinterpret_cast<uint32_t*>(oldp)) != activeMagic())) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
|
@ -58,10 +58,14 @@
|
||||
//
|
||||
// Another thing done in this phase is signal strength handling.
|
||||
// Currently they are only supported in assignments and gates parsed as assignments (see verilog.y)
|
||||
// and only in case when the strongest assignment has RHS marked as non-tristate. It is the case
|
||||
// when they can be statically resolved.
|
||||
// If the RHS is equal to z, that assignment has to be skipped. Since the value may be not known at
|
||||
// verilation time, cases with tristates on RHS can't be handled statically.
|
||||
// when any of the cases occurs:
|
||||
// - it is possible to statically resolve all drivers,
|
||||
// - all assignments that passed the static resolution have symmetric strengths (the same strength
|
||||
// is related to both 0 and 1 values).
|
||||
//
|
||||
// It is possible to statically resolve all drivers when the strongest assignment has RHS marked as
|
||||
// non-tristate. If the RHS is equal to z, that assignment has to be skipped. Since the value may
|
||||
// be not known at verilation time, cases with tristates on RHS can't be handled statically.
|
||||
//
|
||||
// Static resolution is split into 2 parts.
|
||||
// First part can be done before tristate propagation. It is about removing assignments that are
|
||||
@ -85,7 +89,26 @@
|
||||
// - The assignment with non-tristate RHS with the greatest weaker strength has to be found.
|
||||
// - Then all not stronger assignments can be removed.
|
||||
//
|
||||
// All assignments that are stronger than the strongest with non-tristate RHS are left as they are.
|
||||
// All assignments that are stronger than the strongest with non-tristate RHS are then tried to be
|
||||
// handled dynamically. Currently it is supported only on assignments with symmetric strengths.
|
||||
// In this case, the exact value of the RHS doesn't matter. It only matters if it equals z or not.
|
||||
// Such assignments are handled by changing the values to z of these bits that are overwritten by
|
||||
// stronger assignments. Then all assignments can be aggregated as they would have equal strengths
|
||||
// (by | on them and their __en expressions). To change the value to z, the RHS should be & with
|
||||
// negation of __en expression of stronger assignments. Changing RHS's __en expression is not
|
||||
// needed, because it will be then aggregated with __en expression of stronger assignments using |,
|
||||
// so & with the negation can be safely skipped.
|
||||
// So the values of overwritten bits are actually changed to 0, which doesn't affect stronger
|
||||
// assignments, because | operation was used.
|
||||
//
|
||||
// Dynamic handling is implemented in the following way:
|
||||
// - group the assignments by their strengths,
|
||||
// - handle assignments of the same strength by aggregating values with |
|
||||
// - assign results to var__strength and var__strength__en variables
|
||||
// - aggregate the results:
|
||||
// orp = orp | (var__strength & ~enp)
|
||||
// enp = enp | var__strength__en,
|
||||
// where orp is aggregated value and enp is aggregated __en value.
|
||||
//
|
||||
// There is a possible problem with equally strong assignments, because multiple assignments with
|
||||
// the same strength, but different values should result in x value, but these values are
|
||||
@ -384,8 +407,15 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
const VNUser5InUse m_inuser5;
|
||||
|
||||
// TYPES
|
||||
using RefVec = std::vector<AstVarRef*>;
|
||||
using VarMap = std::unordered_map<AstVar*, RefVec*>;
|
||||
struct RefStrength {
|
||||
AstVarRef* m_varrefp;
|
||||
VStrength m_strength;
|
||||
RefStrength(AstVarRef* varrefp, VStrength strength)
|
||||
: m_varrefp{varrefp}
|
||||
, m_strength{strength} {}
|
||||
};
|
||||
using RefStrengthVec = std::vector<RefStrength>;
|
||||
using VarMap = std::unordered_map<AstVar*, RefStrengthVec*>;
|
||||
using Assigns = std::vector<AstAssignW*>;
|
||||
using VarToAssignsMap = std::map<AstVar*, Assigns>;
|
||||
enum : uint8_t {
|
||||
@ -403,6 +433,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
VarToAssignsMap m_assigns; // Assigns in current module
|
||||
int m_unique = 0;
|
||||
bool m_alhs = false; // On LHS of assignment
|
||||
VStrength m_currentStrength = VStrength::STRONG; // Current strength of assignment,
|
||||
// Used only on LHS of assignment
|
||||
const AstNode* m_logicp = nullptr; // Current logic being built
|
||||
TristateGraph m_tgraph; // Logic graph
|
||||
|
||||
@ -485,11 +517,11 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
const auto it = m_lhsmap.find(key);
|
||||
UINFO(9, " mapInsertLhsVarRef " << nodep << endl);
|
||||
if (it == m_lhsmap.end()) { // Not found
|
||||
RefVec* const refsp = new RefVec;
|
||||
refsp->push_back(nodep);
|
||||
RefStrengthVec* const refsp = new RefStrengthVec;
|
||||
refsp->push_back(RefStrength{nodep, m_currentStrength});
|
||||
m_lhsmap.emplace(key, refsp);
|
||||
} else {
|
||||
it->second->push_back(nodep);
|
||||
it->second->push_back(RefStrength{nodep, m_currentStrength});
|
||||
}
|
||||
}
|
||||
|
||||
@ -567,7 +599,7 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
nextit = it;
|
||||
++nextit;
|
||||
AstVar* const invarp = it->first;
|
||||
const RefVec* const refsp = it->second;
|
||||
RefStrengthVec* refsp = it->second;
|
||||
// Figure out if this var needs tristate expanded.
|
||||
if (m_tgraph.isTristate(invarp)) {
|
||||
insertTristatesSignal(nodep, invarp, refsp);
|
||||
@ -580,8 +612,64 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
void insertTristatesSignal(AstNodeModule* nodep, AstVar* const invarp,
|
||||
const RefVec* const refsp) {
|
||||
void aggregateTriSameStrength(AstNodeModule* nodep, AstVar* const varp, AstVar* const envarp,
|
||||
RefStrengthVec::iterator beginStrength,
|
||||
RefStrengthVec::iterator endStrength) {
|
||||
// For each driver seperate variables (normal and __en) are created and initialized with
|
||||
// values. In case of normal variable, the original expression is reused. Their values are
|
||||
// aggregated using | to form one expression, which are assigned to varp end envarp.
|
||||
AstNode* orp = nullptr;
|
||||
AstNode* enp = nullptr;
|
||||
|
||||
for (auto it = beginStrength; it != endStrength; it++) {
|
||||
AstVarRef* refp = it->m_varrefp;
|
||||
const int w = varp->width();
|
||||
|
||||
// create the new lhs driver for this var
|
||||
AstVar* const newLhsp = new AstVar{varp->fileline(), VVarType::MODULETEMP,
|
||||
varp->name() + "__out" + cvtToStr(m_unique),
|
||||
VFlagBitPacked{}, w}; // 2-state ok; sep enable
|
||||
UINFO(9, " newout " << newLhsp << endl);
|
||||
nodep->addStmtsp(newLhsp);
|
||||
refp->varp(newLhsp); // assign the new var to the varref
|
||||
refp->name(newLhsp->name());
|
||||
|
||||
// create a new var for this drivers enable signal
|
||||
AstVar* const newEnLhsp = new AstVar{varp->fileline(), VVarType::MODULETEMP,
|
||||
varp->name() + "__en" + cvtToStr(m_unique++),
|
||||
VFlagBitPacked{}, w}; // 2-state ok
|
||||
UINFO(9, " newenlhsp " << newEnLhsp << endl);
|
||||
nodep->addStmtsp(newEnLhsp);
|
||||
|
||||
AstNode* const enLhspAssignp = new AstAssignW{
|
||||
refp->fileline(), new AstVarRef{refp->fileline(), newEnLhsp, VAccess::WRITE},
|
||||
getEnp(refp)};
|
||||
UINFO(9, " newenlhspAssignp " << enLhspAssignp << endl);
|
||||
nodep->addStmtsp(enLhspAssignp);
|
||||
|
||||
// now append this driver to the driver logic.
|
||||
AstNode* const ref1p = new AstVarRef{refp->fileline(), newLhsp, VAccess::READ};
|
||||
AstNode* const ref2p = new AstVarRef{refp->fileline(), newEnLhsp, VAccess::READ};
|
||||
AstNode* const andp = new AstAnd{refp->fileline(), ref1p, ref2p};
|
||||
|
||||
// or this to the others
|
||||
orp = (!orp) ? andp : new AstOr{refp->fileline(), orp, andp};
|
||||
|
||||
AstNode* const ref3p = new AstVarRef{refp->fileline(), newEnLhsp, VAccess::READ};
|
||||
enp = (!enp) ? ref3p : new AstOr{ref3p->fileline(), enp, ref3p};
|
||||
}
|
||||
AstNode* const assp = new AstAssignW{
|
||||
varp->fileline(), new AstVarRef{varp->fileline(), varp, VAccess::WRITE}, orp};
|
||||
UINFO(9, " newassp " << assp << endl);
|
||||
nodep->addStmtsp(assp);
|
||||
|
||||
AstNode* const enAssp = new AstAssignW{
|
||||
envarp->fileline(), new AstVarRef{envarp->fileline(), envarp, VAccess::WRITE}, enp};
|
||||
UINFO(9, " newenassp " << enAssp << endl);
|
||||
nodep->addStmtsp(enAssp);
|
||||
}
|
||||
|
||||
void insertTristatesSignal(AstNodeModule* nodep, AstVar* const invarp, RefStrengthVec* refsp) {
|
||||
UINFO(8, " TRISTATE EXPANDING:" << invarp << endl);
|
||||
++m_statTriSigs;
|
||||
m_tgraph.didProcess(invarp);
|
||||
@ -615,76 +703,103 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
|
||||
AstNode* orp = nullptr;
|
||||
AstNode* enp = nullptr;
|
||||
AstNode* undrivenp = nullptr;
|
||||
const int w = lhsp->width();
|
||||
|
||||
// loop through the lhs drivers to build the driver resolution logic
|
||||
for (auto refp : *refsp) {
|
||||
const int w = lhsp->width();
|
||||
std::sort(refsp->begin(), refsp->end(),
|
||||
[](RefStrength a, RefStrength b) { return a.m_strength > b.m_strength; });
|
||||
|
||||
// create the new lhs driver for this var
|
||||
AstVar* const newlhsp = new AstVar(lhsp->fileline(), VVarType::MODULETEMP,
|
||||
lhsp->name() + "__out" + cvtToStr(m_unique),
|
||||
VFlagBitPacked(), w); // 2-state ok; sep enable
|
||||
UINFO(9, " newout " << newlhsp << endl);
|
||||
nodep->addStmtsp(newlhsp);
|
||||
refp->varp(newlhsp); // assign the new var to the varref
|
||||
refp->name(newlhsp->name());
|
||||
auto beginStrength = refsp->begin();
|
||||
while (beginStrength != refsp->end()) {
|
||||
auto endStrength = beginStrength + 1;
|
||||
while (endStrength != refsp->end()
|
||||
&& endStrength->m_strength == beginStrength->m_strength)
|
||||
endStrength++;
|
||||
|
||||
// create a new var for this drivers enable signal
|
||||
AstVar* const newenp = new AstVar(lhsp->fileline(), VVarType::MODULETEMP,
|
||||
lhsp->name() + "__en" + cvtToStr(m_unique++),
|
||||
VFlagBitPacked(), w); // 2-state ok
|
||||
UINFO(9, " newenp " << newenp << endl);
|
||||
nodep->addStmtsp(newenp);
|
||||
FileLine* const fl = beginStrength->m_varrefp->fileline();
|
||||
const string strengthVarName = lhsp->name() + "__" + beginStrength->m_strength.ascii();
|
||||
|
||||
AstNode* const enassp = new AstAssignW(
|
||||
refp->fileline(), new AstVarRef(refp->fileline(), newenp, VAccess::WRITE),
|
||||
getEnp(refp));
|
||||
UINFO(9, " newass " << enassp << endl);
|
||||
nodep->addStmtsp(enassp);
|
||||
// var__strength variable
|
||||
AstVar* varStrengthp = new AstVar{fl, VVarType::MODULETEMP, strengthVarName,
|
||||
VFlagBitPacked{}, w}; // 2-state ok; sep enable;
|
||||
UINFO(9, " newstrength " << varStrengthp << endl);
|
||||
nodep->addStmtsp(varStrengthp);
|
||||
|
||||
// now append this driver to the driver logic.
|
||||
AstNode* const ref1p = new AstVarRef(refp->fileline(), newlhsp, VAccess::READ);
|
||||
AstNode* const ref2p = new AstVarRef(refp->fileline(), newenp, VAccess::READ);
|
||||
AstNode* const andp = new AstAnd(refp->fileline(), ref1p, ref2p);
|
||||
// var__strength__en variable
|
||||
AstVar* enVarStrengthp = new AstVar{fl, VVarType::MODULETEMP, strengthVarName + "__en",
|
||||
VFlagBitPacked{}, w}; // 2-state ok;
|
||||
UINFO(9, " newenstrength " << enVarStrengthp << endl);
|
||||
nodep->addStmtsp(enVarStrengthp);
|
||||
|
||||
// or this to the others
|
||||
orp = (!orp) ? andp : new AstOr(refp->fileline(), orp, andp);
|
||||
aggregateTriSameStrength(nodep, varStrengthp, enVarStrengthp, beginStrength,
|
||||
endStrength);
|
||||
|
||||
if (envarp) {
|
||||
AstNode* const ref3p = new AstVarRef(refp->fileline(), newenp, VAccess::READ);
|
||||
enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p);
|
||||
AstNode* exprCurrentStrengthp;
|
||||
if (enp) {
|
||||
// If weaker driver should be overwritten by a stronger, replace its value with z
|
||||
exprCurrentStrengthp
|
||||
= new AstAnd{fl, new AstVarRef{fl, varStrengthp, VAccess::READ},
|
||||
new AstNot{fl, enp->cloneTree(false)}};
|
||||
} else {
|
||||
exprCurrentStrengthp = new AstVarRef{fl, varStrengthp, VAccess::READ};
|
||||
}
|
||||
AstNode* const tmp = new AstNot(
|
||||
newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, VAccess::READ));
|
||||
undrivenp = ((!undrivenp) ? tmp : new AstAnd(refp->fileline(), tmp, undrivenp));
|
||||
}
|
||||
if (!undrivenp) { // No drivers on the bus
|
||||
undrivenp = newAllZerosOrOnes(invarp, true);
|
||||
orp = (!orp) ? exprCurrentStrengthp : new AstOr{fl, orp, exprCurrentStrengthp};
|
||||
|
||||
AstNode* enVarStrengthRefp = new AstVarRef{fl, enVarStrengthp, VAccess::READ};
|
||||
|
||||
enp = (!enp) ? enVarStrengthRefp : new AstOr{fl, enp, enVarStrengthRefp};
|
||||
|
||||
beginStrength = endStrength;
|
||||
}
|
||||
|
||||
if (!outvarp) {
|
||||
// This is the final pre-forced resolution of the tristate, so we apply
|
||||
// the pull direction to any undriven pins.
|
||||
const AstPull* const pullp = static_cast<AstPull*>(lhsp->user3p());
|
||||
bool pull1 = pullp && pullp->direction() == 1; // Else default is down
|
||||
|
||||
AstNode* undrivenp;
|
||||
if (envarp) {
|
||||
undrivenp = new AstNot{envarp->fileline(),
|
||||
new AstVarRef{envarp->fileline(), envarp, VAccess::READ}};
|
||||
} else {
|
||||
if (enp) {
|
||||
undrivenp = new AstNot{enp->fileline(), enp};
|
||||
} else {
|
||||
undrivenp = newAllZerosOrOnes(invarp, true);
|
||||
}
|
||||
}
|
||||
|
||||
undrivenp
|
||||
= new AstAnd{invarp->fileline(), undrivenp, newAllZerosOrOnes(invarp, pull1)};
|
||||
orp = new AstOr(invarp->fileline(), orp, undrivenp);
|
||||
} else {
|
||||
VL_DO_DANGLING(undrivenp->deleteTree(), undrivenp);
|
||||
orp = new AstOr{invarp->fileline(), orp, undrivenp};
|
||||
}
|
||||
|
||||
if (envarp) {
|
||||
nodep->addStmtsp(new AstAssignW(
|
||||
enp->fileline(), new AstVarRef(envarp->fileline(), envarp, VAccess::WRITE), enp));
|
||||
AstAssignW* const enAssp = new AstAssignW{
|
||||
enp->fileline(), new AstVarRef{envarp->fileline(), envarp, VAccess::WRITE}, enp};
|
||||
if (debug() >= 9) enAssp->dumpTree(cout, "enAssp: ");
|
||||
nodep->addStmtsp(enAssp);
|
||||
}
|
||||
|
||||
// __out (child) or <in> (parent) = drive-value expression
|
||||
AstNode* const assp = new AstAssignW(
|
||||
lhsp->fileline(), new AstVarRef(lhsp->fileline(), lhsp, VAccess::WRITE), orp);
|
||||
AstNode* const assp = new AstAssignW{
|
||||
lhsp->fileline(), new AstVarRef{lhsp->fileline(), lhsp, VAccess::WRITE}, orp};
|
||||
assp->user2(U2_BOTH); // Don't process further; already resolved
|
||||
if (debug() >= 9) assp->dumpTree(cout, "-lhsp-eqn: ");
|
||||
nodep->addStmtsp(assp);
|
||||
}
|
||||
|
||||
bool isOnlyAssignmentIsToLhsVar(AstAssignW* const nodep) {
|
||||
if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
||||
auto foundIt = m_assigns.find(varRefp->varp());
|
||||
if (foundIt != m_assigns.end()) {
|
||||
auto const& assignsToVar = foundIt->second;
|
||||
if (assignsToVar.size() == 1 && assignsToVar[0] == nodep) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void addToAssignmentList(AstAssignW* nodep) {
|
||||
if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
||||
if (varRefp->varp()->isNet()) {
|
||||
@ -1109,7 +1224,26 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||
m_tgraph.didProcess(nodep);
|
||||
}
|
||||
m_alhs = true; // And user1p() will indicate tristate equation, if any
|
||||
if (AstAssignW* const assignWp = VN_CAST(nodep, AssignW)) {
|
||||
if (AstStrengthSpec* const specp = assignWp->strengthSpecp()) {
|
||||
if (specp->strength0() != specp->strength1()) {
|
||||
// Unequal strengths are not a problem if the assignment is the only
|
||||
// assignment to its variable. Unfortunately, m_assigns map stores only
|
||||
// assignments to var. Selects are not inserted, so they may be handled
|
||||
// improperly
|
||||
if (!isOnlyAssignmentIsToLhsVar(assignWp)) {
|
||||
assignWp->v3warn(
|
||||
E_UNSUPPORTED,
|
||||
"Unsupported: Unable to resolve unequal strength specifier");
|
||||
}
|
||||
} else {
|
||||
m_currentStrength = specp->strength0();
|
||||
}
|
||||
}
|
||||
}
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
// back to default strength
|
||||
m_currentStrength = VStrength::STRONG;
|
||||
m_alhs = false;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import textwrap
|
||||
|
||||
|
||||
class Node:
|
||||
|
||||
def __init__(self, name, superClass, file, lineno):
|
||||
self._name = name
|
||||
self._superClass = superClass
|
||||
@ -181,6 +182,7 @@ Stages = {}
|
||||
|
||||
|
||||
class Cpt:
|
||||
|
||||
def __init__(self):
|
||||
self.did_out_tree = False
|
||||
self.in_filename = ""
|
||||
|
@ -24,8 +24,8 @@
|
||||
// clang-format on
|
||||
|
||||
#include "V3Number.h"
|
||||
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
||||
#include "V3ParseBison.h" // Generated by bison
|
||||
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
||||
|
||||
#define STATE_VERILOG_RECENT S17 // State name for most recent Verilog Version
|
||||
|
||||
|
@ -23,12 +23,12 @@
|
||||
#endif
|
||||
// clang-format on
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Config.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <cstdlib>
|
||||
#include <stack>
|
||||
|
||||
#define YYERROR_VERBOSE 1 // For prior to Bison 3.6
|
||||
|
@ -13,36 +13,37 @@ scenarios(vlt => 1);
|
||||
if (!$Self->cfg_with_ccache) {
|
||||
skip("Requires configuring with ccache");
|
||||
}
|
||||
else {
|
||||
top_filename("t_a1_first_cc.v");
|
||||
|
||||
top_filename("t_a1_first_cc.v");
|
||||
# This test requires rebuilding the object files to check the ccache log
|
||||
foreach my $filename (glob("$Self->{obj_dir}/*.o")) {
|
||||
print "rm $filename\n" if $Self->{verbose};
|
||||
unlink $filename;
|
||||
}
|
||||
|
||||
# This test requires rebuilding the object files to check the ccache log
|
||||
foreach my $filename (glob("$Self->{obj_dir}/*.o")) {
|
||||
print "rm $filename\n" if $Self->{verbose};
|
||||
unlink $filename;
|
||||
compile(
|
||||
verilator_flags2 => ['--trace'],
|
||||
make_flags => "ccache-report"
|
||||
);
|
||||
|
||||
my $report = "$Self->{obj_dir}/$Self->{VM_PREFIX}__ccache_report.txt";
|
||||
|
||||
# We do not actually want to make this test depend on whether the file was
|
||||
# cached or not, so trim the report to ignore actual caching behaviour
|
||||
run(cmd => ["sed", "-i", "-e", "'s/ : .*/ : IGNORED/; /|/s/.*/IGNORED/;'", $report]);
|
||||
files_identical($report, "t/$Self->{name}__ccache_report_initial.out");
|
||||
|
||||
# Now rebuild again (should be all up to date)
|
||||
run(
|
||||
logfile => "$Self->{obj_dir}/rebuild.log",
|
||||
cmd => ["make", "-C", $Self->{obj_dir},
|
||||
"-f", "$Self->{VM_PREFIX}.mk",
|
||||
$Self->{VM_PREFIX}, "ccache-report"]
|
||||
);
|
||||
|
||||
files_identical($report, "t/$Self->{name}__ccache_report_rebuild.out");
|
||||
}
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--trace'],
|
||||
make_flags => "ccache-report"
|
||||
);
|
||||
|
||||
my $report = "$Self->{obj_dir}/$Self->{VM_PREFIX}__ccache_report.txt";
|
||||
|
||||
# We do not actually want to make this test depend on whether the file was
|
||||
# cached or not, so trim the report to ignore actual caching behaviour
|
||||
run(cmd => ["sed", "-i", "-e", "'s/ : .*/ : IGNORED/; /|/s/.*/IGNORED/;'", $report]);
|
||||
files_identical($report, "t/$Self->{name}__ccache_report_initial.out");
|
||||
|
||||
# Now rebuild again (should be all up to date)
|
||||
run(
|
||||
logfile => "$Self->{obj_dir}/rebuild.log",
|
||||
cmd => ["make", "-C", $Self->{obj_dir},
|
||||
"-f", "$Self->{VM_PREFIX}.mk",
|
||||
$Self->{VM_PREFIX}, "ccache-report"]
|
||||
);
|
||||
|
||||
files_identical($report, "t/$Self->{name}__ccache_report_rebuild.out");
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
@ -1,3 +1,9 @@
|
||||
// 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
|
||||
|
||||
module t
|
||||
(/*AUTOARG*/
|
||||
// Inputs
|
10
test_regress/t/t_strength_2_uneq_assign.out
Normal file
10
test_regress/t/t_strength_2_uneq_assign.out
Normal file
@ -0,0 +1,10 @@
|
||||
%Error-UNSUPPORTED: t/t_strength_2_uneq_assign.v:10:30: Unsupported: Unable to resolve unequal strength specifier
|
||||
: ... In instance t
|
||||
10 | assign (weak0, strong1) a = clk ? 'z : '0;
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_strength_2_uneq_assign.v:11:30: Unsupported: Unable to resolve unequal strength specifier
|
||||
: ... In instance t
|
||||
11 | assign (strong0, pull1) a = 6'b110001;
|
||||
| ^
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_strength_2_uneq_assign.pl
Executable file
19
test_regress/t/t_strength_2_uneq_assign.pl
Executable file
@ -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 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(linter => 1);
|
||||
|
||||
lint(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
19
test_regress/t/t_strength_2_uneq_assign.v
Normal file
19
test_regress/t/t_strength_2_uneq_assign.v
Normal file
@ -0,0 +1,19 @@
|
||||
// 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 (clk);
|
||||
input clk;
|
||||
wire [5:0] a;
|
||||
assign (weak0, strong1) a = clk ? 'z : '0;
|
||||
assign (strong0, pull1) a = 6'b110001;
|
||||
initial begin
|
||||
if (a === 6'b110001) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
21
test_regress/t/t_strength_equal_strength.pl
Executable file
21
test_regress/t/t_strength_equal_strength.pl
Executable file
@ -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;
|
48
test_regress/t/t_strength_equal_strength.v
Normal file
48
test_regress/t/t_strength_equal_strength.v
Normal file
@ -0,0 +1,48 @@
|
||||
// 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
|
||||
|
||||
interface inter (input logic cond, output wire a);
|
||||
parameter W;
|
||||
// Example:
|
||||
wire (weak0, weak1) [W-1:0] b = '1;
|
||||
assign (strong0, strong1) b = cond ? 'b0 : 'bz;
|
||||
|
||||
assign a = b[10];
|
||||
|
||||
endinterface
|
||||
|
||||
module t (clk1, clk2);
|
||||
input wire clk1;
|
||||
input wire clk2;
|
||||
|
||||
wire (weak0, weak1) a = 0;
|
||||
assign (supply0, supply1) a = 1'bz;
|
||||
assign (pull0, pull1) a = 1;
|
||||
|
||||
wire [2:0] b;
|
||||
assign b = 3'b101;
|
||||
assign (supply0, supply1) b = 3'b01z;
|
||||
|
||||
wire c;
|
||||
and (weak0, weak1) (c, clk1, clk2);
|
||||
assign (strong0, strong1) c = 'z;
|
||||
assign (pull0, pull1) c = 0;
|
||||
|
||||
wire d;
|
||||
inter #(.W(32)) i(.cond(1'b1), .a(d));
|
||||
|
||||
always begin
|
||||
if (a === 1 && b === 3'b011 && c === 0 && d === 0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
else begin
|
||||
$write("Error: a = %b, b = %b, c = %b, d = %b", a, b, c, d);
|
||||
$write("expected: a = %b, b = %b, c = %b, d = %b\n", clk1, 3'b011, 0, 0);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
@ -21,6 +21,7 @@
|
||||
|
||||
// General headers
|
||||
#include "verilated.h"
|
||||
|
||||
#include "systemc.h"
|
||||
|
||||
VM_PREFIX* ap;
|
||||
|
Loading…
Reference in New Issue
Block a user