Merge branch 'master' into develop-v5
This commit is contained in:
commit
c6bce636ee
|
|
@ -10,11 +10,11 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
format:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
name: Ubuntu 20.04 | format
|
name: Ubuntu 22.04 | format
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: linux
|
CI_OS_NAME: linux
|
||||||
CI_RUNS_ON: ubuntu-20.04
|
CI_RUNS_ON: ubuntu-22.04
|
||||||
CI_COMMIT: ${{ github.sha }}
|
CI_COMMIT: ${{ github.sha }}
|
||||||
CI_M32: 0
|
CI_M32: 0
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -27,14 +27,14 @@ jobs:
|
||||||
CI_BUILD_STAGE_NAME: build
|
CI_BUILD_STAGE_NAME: build
|
||||||
run: |
|
run: |
|
||||||
bash ci/ci-install.bash &&
|
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.email "action@example.com" &&
|
||||||
git config --global user.name "github action"
|
git config --global user.name "github action"
|
||||||
- name: Format code
|
- name: Format code
|
||||||
run: |
|
run: |
|
||||||
autoconf &&
|
autoconf &&
|
||||||
./configure &&
|
./configure &&
|
||||||
make -j 2 format CLANGFORMAT=clang-format-11 &&
|
make -j 2 format CLANGFORMAT=clang-format-14 &&
|
||||||
git status
|
git status
|
||||||
- name: Push
|
- name: Push
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -346,13 +346,13 @@ analyzer-include:
|
||||||
|
|
||||||
format: clang-format yapf format-pl-exec
|
format: clang-format yapf format-pl-exec
|
||||||
|
|
||||||
CLANGFORMAT = clang-format-11
|
CLANGFORMAT = clang-format-14
|
||||||
CLANGFORMAT_FLAGS = -i
|
CLANGFORMAT_FLAGS = -i
|
||||||
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* test_regress/t/*.h
|
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* test_regress/t/*.h
|
||||||
|
|
||||||
clang-format:
|
clang-format:
|
||||||
@$(CLANGFORMAT) --version | egrep 11.0 > /dev/null \
|
@$(CLANGFORMAT) --version | egrep 14.0 > /dev/null \
|
||||||
|| echo "*** You are not using clang-format 11.0, indents may differ from master's ***"
|
|| echo "*** You are not using clang-format-14, indents may differ from master's ***"
|
||||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
||||||
|
|
||||||
PY_PROGRAMS = \
|
PY_PROGRAMS = \
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ HyungKi Jeong
|
||||||
Iru Cai
|
Iru Cai
|
||||||
Ivan Vnučec
|
Ivan Vnučec
|
||||||
Iztok Jeras
|
Iztok Jeras
|
||||||
|
Jake Merdich
|
||||||
James Hanlon
|
James Hanlon
|
||||||
James Hutchinson
|
James Hutchinson
|
||||||
James Pallister
|
James Pallister
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ from datetime import datetime
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath('./_ext'))
|
sys.path.insert(0, os.path.abspath('./_ext'))
|
||||||
|
|
||||||
import sphinx_rtd_theme # pylint: disable=wrong-import-position,
|
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 apt-get install yapf3
|
||||||
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe
|
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe
|
||||||
cpan install Pod::Perldoc
|
cpan install Pod::Perldoc
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,13 @@ from shutil import copy2
|
||||||
|
|
||||||
|
|
||||||
class VlFileCopy:
|
class VlFileCopy:
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
verilator_args, # presently all verilator options are passed-thru
|
verilator_args, # presently all verilator options are passed-thru
|
||||||
# ideally this script would check against options mentioned in help
|
# ideally this script would check against options mentioned in help
|
||||||
debug=0,
|
debug=0,
|
||||||
output_dir='copied'): # directory name we output file uses
|
output_dir='copied'): # directory name we output file uses
|
||||||
|
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,13 @@ import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
class VlHierGraph:
|
class VlHierGraph:
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
verilator_args, # presently all verilator options are passed-thru
|
verilator_args, # presently all verilator options are passed-thru
|
||||||
# ideally this script would check against options mentioned in help
|
# ideally this script would check against options mentioned in help
|
||||||
debug=0,
|
debug=0,
|
||||||
output_filename='graph.dot'): # output filename
|
output_filename='graph.dot'): # output filename
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.next_vertex_number = 0
|
self.next_vertex_number = 0
|
||||||
self.name_to_number = {}
|
self.name_to_number = {}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ public:
|
||||||
*(reinterpret_cast<uint32_t*>(newp)) = activeMagic();
|
*(reinterpret_cast<uint32_t*>(newp)) = activeMagic();
|
||||||
return newp + 8;
|
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;
|
uint8_t* const oldp = (static_cast<uint8_t*>(obj)) - 8;
|
||||||
if (VL_UNLIKELY(*(reinterpret_cast<uint32_t*>(oldp)) != activeMagic())) {
|
if (VL_UNLIKELY(*(reinterpret_cast<uint32_t*>(oldp)) != activeMagic())) {
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,14 @@
|
||||||
//
|
//
|
||||||
// Another thing done in this phase is signal strength handling.
|
// 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)
|
// 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 any of the cases occurs:
|
||||||
// when they can be statically resolved.
|
// - it is possible to statically resolve all drivers,
|
||||||
// If the RHS is equal to z, that assignment has to be skipped. Since the value may be not known at
|
// - all assignments that passed the static resolution have symmetric strengths (the same strength
|
||||||
// verilation time, cases with tristates on RHS can't be handled statically.
|
// 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.
|
// Static resolution is split into 2 parts.
|
||||||
// First part can be done before tristate propagation. It is about removing assignments that are
|
// 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.
|
// - The assignment with non-tristate RHS with the greatest weaker strength has to be found.
|
||||||
// - Then all not stronger assignments can be removed.
|
// - 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
|
// 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
|
// 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;
|
const VNUser5InUse m_inuser5;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
using RefVec = std::vector<AstVarRef*>;
|
struct RefStrength {
|
||||||
using VarMap = std::unordered_map<AstVar*, RefVec*>;
|
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 Assigns = std::vector<AstAssignW*>;
|
||||||
using VarToAssignsMap = std::map<AstVar*, Assigns>;
|
using VarToAssignsMap = std::map<AstVar*, Assigns>;
|
||||||
enum : uint8_t {
|
enum : uint8_t {
|
||||||
|
|
@ -403,6 +433,8 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||||
VarToAssignsMap m_assigns; // Assigns in current module
|
VarToAssignsMap m_assigns; // Assigns in current module
|
||||||
int m_unique = 0;
|
int m_unique = 0;
|
||||||
bool m_alhs = false; // On LHS of assignment
|
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
|
const AstNode* m_logicp = nullptr; // Current logic being built
|
||||||
TristateGraph m_tgraph; // Logic graph
|
TristateGraph m_tgraph; // Logic graph
|
||||||
|
|
||||||
|
|
@ -485,11 +517,11 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||||
const auto it = m_lhsmap.find(key);
|
const auto it = m_lhsmap.find(key);
|
||||||
UINFO(9, " mapInsertLhsVarRef " << nodep << endl);
|
UINFO(9, " mapInsertLhsVarRef " << nodep << endl);
|
||||||
if (it == m_lhsmap.end()) { // Not found
|
if (it == m_lhsmap.end()) { // Not found
|
||||||
RefVec* const refsp = new RefVec;
|
RefStrengthVec* const refsp = new RefStrengthVec;
|
||||||
refsp->push_back(nodep);
|
refsp->push_back(RefStrength{nodep, m_currentStrength});
|
||||||
m_lhsmap.emplace(key, refsp);
|
m_lhsmap.emplace(key, refsp);
|
||||||
} else {
|
} 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 = it;
|
||||||
++nextit;
|
++nextit;
|
||||||
AstVar* const invarp = it->first;
|
AstVar* const invarp = it->first;
|
||||||
const RefVec* const refsp = it->second;
|
RefStrengthVec* refsp = it->second;
|
||||||
// Figure out if this var needs tristate expanded.
|
// Figure out if this var needs tristate expanded.
|
||||||
if (m_tgraph.isTristate(invarp)) {
|
if (m_tgraph.isTristate(invarp)) {
|
||||||
insertTristatesSignal(nodep, invarp, refsp);
|
insertTristatesSignal(nodep, invarp, refsp);
|
||||||
|
|
@ -580,8 +612,64 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertTristatesSignal(AstNodeModule* nodep, AstVar* const invarp,
|
void aggregateTriSameStrength(AstNodeModule* nodep, AstVar* const varp, AstVar* const envarp,
|
||||||
const RefVec* const refsp) {
|
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);
|
UINFO(8, " TRISTATE EXPANDING:" << invarp << endl);
|
||||||
++m_statTriSigs;
|
++m_statTriSigs;
|
||||||
m_tgraph.didProcess(invarp);
|
m_tgraph.didProcess(invarp);
|
||||||
|
|
@ -615,76 +703,103 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||||
|
|
||||||
AstNode* orp = nullptr;
|
AstNode* orp = nullptr;
|
||||||
AstNode* enp = nullptr;
|
AstNode* enp = nullptr;
|
||||||
AstNode* undrivenp = nullptr;
|
const int w = lhsp->width();
|
||||||
|
|
||||||
// loop through the lhs drivers to build the driver resolution logic
|
std::sort(refsp->begin(), refsp->end(),
|
||||||
for (auto refp : *refsp) {
|
[](RefStrength a, RefStrength b) { return a.m_strength > b.m_strength; });
|
||||||
const int w = lhsp->width();
|
|
||||||
|
|
||||||
// create the new lhs driver for this var
|
auto beginStrength = refsp->begin();
|
||||||
AstVar* const newlhsp = new AstVar(lhsp->fileline(), VVarType::MODULETEMP,
|
while (beginStrength != refsp->end()) {
|
||||||
lhsp->name() + "__out" + cvtToStr(m_unique),
|
auto endStrength = beginStrength + 1;
|
||||||
VFlagBitPacked(), w); // 2-state ok; sep enable
|
while (endStrength != refsp->end()
|
||||||
UINFO(9, " newout " << newlhsp << endl);
|
&& endStrength->m_strength == beginStrength->m_strength)
|
||||||
nodep->addStmtsp(newlhsp);
|
endStrength++;
|
||||||
refp->varp(newlhsp); // assign the new var to the varref
|
|
||||||
refp->name(newlhsp->name());
|
|
||||||
|
|
||||||
// create a new var for this drivers enable signal
|
FileLine* const fl = beginStrength->m_varrefp->fileline();
|
||||||
AstVar* const newenp = new AstVar(lhsp->fileline(), VVarType::MODULETEMP,
|
const string strengthVarName = lhsp->name() + "__" + beginStrength->m_strength.ascii();
|
||||||
lhsp->name() + "__en" + cvtToStr(m_unique++),
|
|
||||||
VFlagBitPacked(), w); // 2-state ok
|
|
||||||
UINFO(9, " newenp " << newenp << endl);
|
|
||||||
nodep->addStmtsp(newenp);
|
|
||||||
|
|
||||||
AstNode* const enassp = new AstAssignW(
|
// var__strength variable
|
||||||
refp->fileline(), new AstVarRef(refp->fileline(), newenp, VAccess::WRITE),
|
AstVar* varStrengthp = new AstVar{fl, VVarType::MODULETEMP, strengthVarName,
|
||||||
getEnp(refp));
|
VFlagBitPacked{}, w}; // 2-state ok; sep enable;
|
||||||
UINFO(9, " newass " << enassp << endl);
|
UINFO(9, " newstrength " << varStrengthp << endl);
|
||||||
nodep->addStmtsp(enassp);
|
nodep->addStmtsp(varStrengthp);
|
||||||
|
|
||||||
// now append this driver to the driver logic.
|
// var__strength__en variable
|
||||||
AstNode* const ref1p = new AstVarRef(refp->fileline(), newlhsp, VAccess::READ);
|
AstVar* enVarStrengthp = new AstVar{fl, VVarType::MODULETEMP, strengthVarName + "__en",
|
||||||
AstNode* const ref2p = new AstVarRef(refp->fileline(), newenp, VAccess::READ);
|
VFlagBitPacked{}, w}; // 2-state ok;
|
||||||
AstNode* const andp = new AstAnd(refp->fileline(), ref1p, ref2p);
|
UINFO(9, " newenstrength " << enVarStrengthp << endl);
|
||||||
|
nodep->addStmtsp(enVarStrengthp);
|
||||||
|
|
||||||
// or this to the others
|
aggregateTriSameStrength(nodep, varStrengthp, enVarStrengthp, beginStrength,
|
||||||
orp = (!orp) ? andp : new AstOr(refp->fileline(), orp, andp);
|
endStrength);
|
||||||
|
|
||||||
if (envarp) {
|
AstNode* exprCurrentStrengthp;
|
||||||
AstNode* const ref3p = new AstVarRef(refp->fileline(), newenp, VAccess::READ);
|
if (enp) {
|
||||||
enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p);
|
// 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(
|
orp = (!orp) ? exprCurrentStrengthp : new AstOr{fl, orp, exprCurrentStrengthp};
|
||||||
newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, VAccess::READ));
|
|
||||||
undrivenp = ((!undrivenp) ? tmp : new AstAnd(refp->fileline(), tmp, undrivenp));
|
AstNode* enVarStrengthRefp = new AstVarRef{fl, enVarStrengthp, VAccess::READ};
|
||||||
}
|
|
||||||
if (!undrivenp) { // No drivers on the bus
|
enp = (!enp) ? enVarStrengthRefp : new AstOr{fl, enp, enVarStrengthRefp};
|
||||||
undrivenp = newAllZerosOrOnes(invarp, true);
|
|
||||||
|
beginStrength = endStrength;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!outvarp) {
|
if (!outvarp) {
|
||||||
// This is the final pre-forced resolution of the tristate, so we apply
|
// This is the final pre-forced resolution of the tristate, so we apply
|
||||||
// the pull direction to any undriven pins.
|
// the pull direction to any undriven pins.
|
||||||
const AstPull* const pullp = static_cast<AstPull*>(lhsp->user3p());
|
const AstPull* const pullp = static_cast<AstPull*>(lhsp->user3p());
|
||||||
bool pull1 = pullp && pullp->direction() == 1; // Else default is down
|
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
|
undrivenp
|
||||||
= new AstAnd{invarp->fileline(), undrivenp, newAllZerosOrOnes(invarp, pull1)};
|
= new AstAnd{invarp->fileline(), undrivenp, newAllZerosOrOnes(invarp, pull1)};
|
||||||
orp = new AstOr(invarp->fileline(), orp, undrivenp);
|
orp = new AstOr{invarp->fileline(), orp, undrivenp};
|
||||||
} else {
|
|
||||||
VL_DO_DANGLING(undrivenp->deleteTree(), undrivenp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (envarp) {
|
if (envarp) {
|
||||||
nodep->addStmtsp(new AstAssignW(
|
AstAssignW* const enAssp = new AstAssignW{
|
||||||
enp->fileline(), new AstVarRef(envarp->fileline(), envarp, VAccess::WRITE), enp));
|
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
|
// __out (child) or <in> (parent) = drive-value expression
|
||||||
AstNode* const assp = new AstAssignW(
|
AstNode* const assp = new AstAssignW{
|
||||||
lhsp->fileline(), new AstVarRef(lhsp->fileline(), lhsp, VAccess::WRITE), orp);
|
lhsp->fileline(), new AstVarRef{lhsp->fileline(), lhsp, VAccess::WRITE}, orp};
|
||||||
assp->user2(U2_BOTH); // Don't process further; already resolved
|
assp->user2(U2_BOTH); // Don't process further; already resolved
|
||||||
if (debug() >= 9) assp->dumpTree(cout, "-lhsp-eqn: ");
|
if (debug() >= 9) assp->dumpTree(cout, "-lhsp-eqn: ");
|
||||||
nodep->addStmtsp(assp);
|
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) {
|
void addToAssignmentList(AstAssignW* nodep) {
|
||||||
if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
||||||
if (varRefp->varp()->isNet()) {
|
if (varRefp->varp()->isNet()) {
|
||||||
|
|
@ -1109,7 +1224,26 @@ class TristateVisitor final : public TristateBaseVisitor {
|
||||||
m_tgraph.didProcess(nodep);
|
m_tgraph.didProcess(nodep);
|
||||||
}
|
}
|
||||||
m_alhs = true; // And user1p() will indicate tristate equation, if any
|
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());
|
iterateAndNextNull(nodep->lhsp());
|
||||||
|
// back to default strength
|
||||||
|
m_currentStrength = VStrength::STRONG;
|
||||||
m_alhs = false;
|
m_alhs = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import textwrap
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
|
|
||||||
def __init__(self, name, superClass, file, lineno):
|
def __init__(self, name, superClass, file, lineno):
|
||||||
self._name = name
|
self._name = name
|
||||||
self._superClass = superClass
|
self._superClass = superClass
|
||||||
|
|
@ -181,6 +182,7 @@ Stages = {}
|
||||||
|
|
||||||
|
|
||||||
class Cpt:
|
class Cpt:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.did_out_tree = False
|
self.did_out_tree = False
|
||||||
self.in_filename = ""
|
self.in_filename = ""
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#include "V3Number.h"
|
#include "V3Number.h"
|
||||||
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
|
||||||
#include "V3ParseBison.h" // Generated by bison
|
#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
|
#define STATE_VERILOG_RECENT S17 // State name for most recent Verilog Version
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@
|
||||||
#endif
|
#endif
|
||||||
// clang-format on
|
// clang-format on
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
#include "V3Global.h"
|
|
||||||
#include "V3Config.h"
|
#include "V3Config.h"
|
||||||
|
#include "V3Global.h"
|
||||||
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
#include <cstdlib>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
#define YYERROR_VERBOSE 1 // For prior to Bison 3.6
|
#define YYERROR_VERBOSE 1 // For prior to Bison 3.6
|
||||||
|
|
|
||||||
|
|
@ -13,36 +13,37 @@ scenarios(vlt => 1);
|
||||||
if (!$Self->cfg_with_ccache) {
|
if (!$Self->cfg_with_ccache) {
|
||||||
skip("Requires configuring 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
|
compile(
|
||||||
foreach my $filename (glob("$Self->{obj_dir}/*.o")) {
|
verilator_flags2 => ['--trace'],
|
||||||
print "rm $filename\n" if $Self->{verbose};
|
make_flags => "ccache-report"
|
||||||
unlink $filename;
|
);
|
||||||
|
|
||||||
|
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);
|
ok(1);
|
||||||
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
|
module t
|
||||||
(/*AUTOARG*/
|
(/*AUTOARG*/
|
||||||
// Inputs
|
// Inputs
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2022 by Antmicro Ltd. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,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
|
// General headers
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
|
|
||||||
#include "systemc.h"
|
#include "systemc.h"
|
||||||
|
|
||||||
VM_PREFIX* ap;
|
VM_PREFIX* ap;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue