Merge branch 'master' into fix/73-dist
This commit is contained in:
commit
31aeced75b
|
|
@ -155,7 +155,7 @@ jobs:
|
|||
- name: Zip up repository
|
||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
||||
- name: Upload zip archive
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/verilator.zip
|
||||
name: verilator-win.zip
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ jobs:
|
|||
uses: actions/checkout@v6
|
||||
|
||||
- name: Download code coverage data
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: code-coverage-*
|
||||
path: obj_coverage
|
||||
|
|
@ -114,7 +114,7 @@ jobs:
|
|||
sudo apt install lcov
|
||||
|
||||
- name: Download repository archive
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: ${{ needs.build.outputs.archive }}
|
||||
path: ${{ github.workspace }}
|
||||
|
|
@ -125,7 +125,7 @@ jobs:
|
|||
ls -lsha
|
||||
|
||||
- name: Download code coverage data
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: code-coverage-*
|
||||
path: repo/obj_coverage
|
||||
|
|
@ -170,14 +170,14 @@ jobs:
|
|||
fi
|
||||
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: repo/obj_coverage
|
||||
name: coverage-report
|
||||
|
||||
- name: Upload notification
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: repo/notification
|
||||
name: coverage-pr-notification
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ jobs:
|
|||
echo "archive=$ARCHIVE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload repository archive
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ steps.create-archive.outputs.archive }}
|
||||
name: ${{ steps.create-archive.outputs.archive }}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ jobs:
|
|||
run: tar --posix -c -z -f verilator-rtlmeter.tar.gz install
|
||||
|
||||
- name: Upload Verilator installation archive
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: verilator-rtlmeter.tar.gz
|
||||
name: verilator-rtlmeter-${{ inputs.runs-on }}-${{ inputs.cc }}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ jobs:
|
|||
sudo apt install ccache mold libfl-dev libgoogle-perftools-dev libsystemc-dev
|
||||
|
||||
- name: Download Verilator installation archive
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: verilator-rtlmeter-${{ inputs.runs-on }}-${{ inputs.cc }}
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ jobs:
|
|||
./rtlmeter report --steps '*' --metrics '*' ../results-${{ steps.results.outputs.hash }}.json
|
||||
|
||||
- name: Upload results
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: results-${{ steps.results.outputs.hash }}.json
|
||||
name: rtlmeter-${{ inputs.tag }}-results-${{ steps.results.outputs.hash }}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ jobs:
|
|||
steps:
|
||||
|
||||
- name: Download repository archive
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: ${{ inputs.archive }}
|
||||
path: ${{ github.workspace }}
|
||||
|
|
@ -99,7 +99,7 @@ jobs:
|
|||
|
||||
- name: Upload code coverage data
|
||||
if: ${{ inputs.dev-gcov }}
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/obj_coverage/verilator-${{ inputs.suite }}.info
|
||||
name: code-coverage-${{ inputs.suite }}
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@ jobs:
|
|||
pull-requests: write
|
||||
steps:
|
||||
- name: Download report
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: rtlmeter-pr-results
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Download PR number
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: pr-number
|
||||
run-id: ${{ github.event.workflow_run.id }}
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ jobs:
|
|||
working-directory: rtlmeter
|
||||
run: make venv
|
||||
- name: Download all results
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: rtlmeter-${{ matrix.tag }}-results-*
|
||||
path: all-results-${{ matrix.tag }}
|
||||
|
|
@ -208,7 +208,7 @@ jobs:
|
|||
run: |
|
||||
./rtlmeter collate ../all-results-${{ matrix.tag }}/*.json > ../all-results-${{ matrix.tag }}.json
|
||||
- name: Upload combined results
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: all-results-${{ matrix.tag }}.json
|
||||
name: all-results-${{ matrix.tag }}
|
||||
|
|
@ -227,13 +227,13 @@ jobs:
|
|||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Download combined results
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: all-results-*
|
||||
path: results
|
||||
merge-multiple: true
|
||||
- name: Upload published results
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: results/*.json
|
||||
name: published-results
|
||||
|
|
@ -289,7 +289,7 @@ jobs:
|
|||
working-directory: rtlmeter
|
||||
run: make venv
|
||||
- name: Download combined results
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: all-results-*
|
||||
path: all-results
|
||||
|
|
@ -308,7 +308,7 @@ jobs:
|
|||
DATE=$(gh run --repo ${{ github.repository }} view $ID --json createdAt --jq ".createdAt")
|
||||
echo "date=$DATE" >> $GITHUB_OUTPUT
|
||||
- name: Download scheduled run results
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: published-results
|
||||
path: nightly-results
|
||||
|
|
@ -374,14 +374,14 @@ jobs:
|
|||
done
|
||||
cat report.txt
|
||||
- name: Upload report
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: report.txt
|
||||
name: rtlmeter-pr-results
|
||||
- name: Save PR number
|
||||
run: echo ${{ github.event.number }} > pr-number.txt
|
||||
- name: Upload PR number
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: pr-number.txt
|
||||
name: pr-number
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ Ivan Vnučec
|
|||
Iztok Jeras
|
||||
Jake Merdich
|
||||
Jakub Wasilewski
|
||||
jalcim
|
||||
James Bailey
|
||||
James Hanlon
|
||||
James Hutchinson
|
||||
|
|
|
|||
|
|
@ -496,6 +496,9 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
|||
std::iostream& os = getSolver();
|
||||
if (!os) return false;
|
||||
|
||||
// Soft constraint relaxation (IEEE 1800-2017 18.5.13, last-wins priority):
|
||||
// Try hard + soft[0..N-1], then hard + soft[1..N-1], ..., then hard only.
|
||||
// First SAT phase wins. If hard-only is UNSAT, report via unsat-core.
|
||||
os << "(set-option :produce-models true)\n";
|
||||
os << "(set-logic QF_ABV)\n";
|
||||
os << "(define-fun __Vbv ((b Bool)) (_ BitVec 1) (ite b #b1 #b0))\n";
|
||||
|
|
@ -520,9 +523,20 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
|||
os << "(assert (= " << pair.first << " (_ bv" << pair.second << " " << w << ")))\n";
|
||||
}
|
||||
|
||||
os << "(check-sat)\n";
|
||||
const size_t nSoft = m_softConstraints.size();
|
||||
bool sat = false;
|
||||
for (size_t phase = 0; phase <= nSoft && !sat; ++phase) {
|
||||
const bool hasSoft = (phase < nSoft);
|
||||
if (hasSoft) {
|
||||
os << "(push 1)\n";
|
||||
for (size_t i = phase; i < nSoft; ++i)
|
||||
os << "(assert (= #b1 " << m_softConstraints[i] << "))\n";
|
||||
}
|
||||
os << "(check-sat)\n";
|
||||
sat = parseSolution(os, /*log=*/phase == nSoft);
|
||||
if (!sat && hasSoft) os << "(pop 1)\n";
|
||||
}
|
||||
|
||||
bool sat = parseSolution(os, true);
|
||||
if (!sat) {
|
||||
// If unsat, use named assertions to get unsat-core
|
||||
os << "(reset)\n";
|
||||
|
|
@ -541,8 +555,11 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
|||
}
|
||||
int j = 0;
|
||||
for (const std::string& constraint : m_constraints) {
|
||||
os << "(assert (! (= #b1 " << constraint << ") :named cons" << j << "))\n";
|
||||
j++;
|
||||
os << "(assert (! (= #b1 " << constraint << ") :named cons" << j++ << "))\n";
|
||||
}
|
||||
for (const auto& pair : randcPinned) {
|
||||
const int w = m_vars.at(pair.first)->width();
|
||||
os << "(assert (= " << pair.first << " (_ bv" << pair.second << " " << w << ")))\n";
|
||||
}
|
||||
os << "(check-sat)\n";
|
||||
sat = parseSolution(os, true);
|
||||
|
|
@ -550,6 +567,7 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
|||
os << "(reset)\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _VL_SOLVER_HASH_LEN_TOTAL && sat; ++i) {
|
||||
os << "(assert ";
|
||||
randomConstraint(os, rngr, _VL_SOLVER_HASH_LEN);
|
||||
|
|
@ -723,15 +741,22 @@ void VlRandomizer::hard(std::string&& constraint, const char* filename, uint32_t
|
|||
}
|
||||
}
|
||||
|
||||
void VlRandomizer::soft(std::string&& constraint, const char* /*filename*/, uint32_t /*linenum*/,
|
||||
const char* /*source*/) {
|
||||
m_softConstraints.emplace_back(std::move(constraint));
|
||||
}
|
||||
|
||||
void VlRandomizer::clearConstraints() {
|
||||
m_constraints.clear();
|
||||
m_constraints_line.clear();
|
||||
m_solveBefore.clear();
|
||||
m_softConstraints.clear();
|
||||
// Keep m_vars for class member randomization
|
||||
}
|
||||
|
||||
void VlRandomizer::clearAll() {
|
||||
m_constraints.clear();
|
||||
m_softConstraints.clear();
|
||||
m_vars.clear();
|
||||
m_randcVarNames.clear();
|
||||
m_randcValueQueues.clear();
|
||||
|
|
|
|||
|
|
@ -200,9 +200,10 @@ public:
|
|||
// Object holding constraints and variable references.
|
||||
class VlRandomizer VL_NOT_FINAL {
|
||||
// MEMBERS
|
||||
std::vector<std::string> m_constraints; // Solver-dependent constraints
|
||||
std::vector<std::string> m_constraints; // Solver-dependent hard constraints
|
||||
std::vector<std::string>
|
||||
m_constraints_line; // fileline content of the constraint for unsat constraints
|
||||
std::vector<std::string> m_softConstraints; // Soft constraints
|
||||
std::map<std::string, std::shared_ptr<const VlRandomVar>> m_vars; // Solver-dependent
|
||||
// variables
|
||||
ArrayInfoMap m_arr_vars; // Tracks each element in array structures for iteration
|
||||
|
|
@ -593,6 +594,8 @@ public:
|
|||
|
||||
void hard(std::string&& constraint, const char* filename = "", uint32_t linenum = 0,
|
||||
const char* source = "");
|
||||
void soft(std::string&& constraint, const char* filename = "", uint32_t linenum = 0,
|
||||
const char* source = "");
|
||||
void clearConstraints();
|
||||
void clearAll(); // Clear both constraints and variables
|
||||
void markRandc(const char* name); // Mark variable as randc for cyclic tracking
|
||||
|
|
|
|||
|
|
@ -65,8 +65,9 @@ set(HEADERS
|
|||
V3Clock.h
|
||||
V3Combine.h
|
||||
V3Common.h
|
||||
V3Control.h
|
||||
V3Const.h
|
||||
V3Container.h
|
||||
V3Control.h
|
||||
V3Coverage.h
|
||||
V3CoverageJoin.h
|
||||
V3Dead.h
|
||||
|
|
|
|||
|
|
@ -815,6 +815,7 @@ public:
|
|||
RANDOMIZER_CLEARCONSTRAINTS,
|
||||
RANDOMIZER_CLEARALL,
|
||||
RANDOMIZER_HARD,
|
||||
RANDOMIZER_SOFT,
|
||||
RANDOMIZER_UNIQUE,
|
||||
RANDOMIZER_MARK_RANDC,
|
||||
RANDOMIZER_SOLVE_BEFORE,
|
||||
|
|
@ -951,6 +952,7 @@ inline std::ostream& operator<<(std::ostream& os, const VCMethod& rhs) {
|
|||
{RANDOMIZER_CLEARCONSTRAINTS, "clearConstraints", false}, \
|
||||
{RANDOMIZER_CLEARALL, "clearAll", false}, \
|
||||
{RANDOMIZER_HARD, "hard", false}, \
|
||||
{RANDOMIZER_SOFT, "soft", false}, \
|
||||
{RANDOMIZER_UNIQUE, "rand_unique", false}, \
|
||||
{RANDOMIZER_MARK_RANDC, "markRandc", false}, \
|
||||
{RANDOMIZER_SOLVE_BEFORE, "solveBefore", false}, \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Generic container types
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// 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-FileCopyrightText: 2003-2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3CONTAINER_H_
|
||||
#define VERILATOR_V3CONTAINER_H_
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
//============================================================================
|
||||
|
||||
// Similar to std::set, but ordered based on call order to emplace. Used
|
||||
// when insertion order is desired (e.g. std::vector), but duplicates need removal.
|
||||
// Keys may not be modified. (If needed in future, m_set could contain vector positions.)
|
||||
template <typename T_Key>
|
||||
class VInsertionSet final {
|
||||
std::vector<T_Key> m_keys; // Elements by insertion order
|
||||
std::unordered_set<T_Key> m_keySet; // Elements by key
|
||||
public:
|
||||
// METHODS
|
||||
bool insert(const T_Key& key) {
|
||||
// Returns if did insertion (second pair argument of traditional emplace)
|
||||
const auto itFoundPair = m_keySet.insert(key);
|
||||
if (itFoundPair.second) m_keys.push_back(key);
|
||||
return itFoundPair.second;
|
||||
}
|
||||
void clear() {
|
||||
m_keys.clear();
|
||||
m_keySet.clear();
|
||||
}
|
||||
|
||||
// ACCESSORS
|
||||
bool empty() const { return m_keys.empty(); }
|
||||
bool exists(const T_Key& key) const { return m_keySet.find(key) != m_keySet.end(); }
|
||||
|
||||
// ITERATORS
|
||||
using const_iterator = typename std::vector<T_Key>::const_iterator;
|
||||
const_iterator begin() const { return m_keys.begin(); }
|
||||
const_iterator end() const { return m_keys.end(); }
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
// VInsertionMap: Not currently needed; prototype code exists, just ask.
|
||||
// Similar to std::map, but ordered based on call order to emplace. Used
|
||||
// when insertion order is desired (e.g. std::vector), but duplicates need removal.
|
||||
// Values may be modified.
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -263,7 +263,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||
AstUser3Allocator<AstVarScope, std::vector<WriteReference>> m_writeRefs;
|
||||
|
||||
// STATE - across all visitors
|
||||
std::set<AstSenTree*> m_timingDomains; // Timing resume domains
|
||||
VInsertionSet<AstSenTree*> m_timingDomains; // Timing resume domains
|
||||
|
||||
// STATE - for current visit position (use VL_RESTORER)
|
||||
AstActive* m_activep = nullptr; // Current activate
|
||||
|
|
|
|||
|
|
@ -734,8 +734,8 @@ public:
|
|||
puts(";\n");
|
||||
}
|
||||
void visit(AstCNew* nodep) override {
|
||||
if (VN_IS(nodep->dtypep(), VoidDType)) {
|
||||
// super.new case
|
||||
if (VN_IS(nodep->dtypep(), VoidDType)) { // super.new case
|
||||
putsDecoration(nodep, "/*super.new*/");
|
||||
return;
|
||||
}
|
||||
// assignment case;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "V3Options.h"
|
||||
|
||||
#include "V3Container.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Global.h"
|
||||
|
|
@ -70,30 +71,26 @@ public:
|
|||
std::list<string> m_lineArgs; // List of command line argument encountered
|
||||
// List of arguments encounterd, and a bool in needed for rerunning --dump-inputs
|
||||
std::list<std::pair<std::list<std::string>, bool>> m_allArgs;
|
||||
std::list<string> m_incDirUsers; // Include directories (ordered)
|
||||
std::set<string> m_incDirUserSet; // Include directories (for removing duplicates)
|
||||
VInsertionSet<std::string> m_incDirUsers; // Include directories (ordered)
|
||||
std::list<string> m_incDirFallbacks; // Include directories (ordered)
|
||||
std::set<string> m_incDirFallbackSet; // Include directories (for removing duplicates)
|
||||
std::map<const string, V3LangCode> m_langExts; // Language extension map
|
||||
std::list<string> m_libExtVs; // Library extensions (ordered)
|
||||
std::set<string> m_libExtVSet; // Library extensions (for removing duplicates)
|
||||
VInsertionSet<std::string> m_libExtVs; // Library extensions (ordered)
|
||||
DirMap m_dirMap; // Directory listing
|
||||
|
||||
// ACCESSOR METHODS
|
||||
void addIncDirUser(const string& incdir) {
|
||||
const string& dir = V3Os::filenameCleanup(incdir);
|
||||
const auto itFoundPair = m_incDirUserSet.insert(dir);
|
||||
if (itFoundPair.second) {
|
||||
const bool inserted = m_incDirUsers.insert(dir);
|
||||
if (inserted) {
|
||||
// cppcheck-suppress stlFindInsert // cppcheck 1.90 bug
|
||||
m_incDirUsers.push_back(dir);
|
||||
m_incDirFallbacks.remove(dir); // User has priority over Fallback
|
||||
m_incDirFallbackSet.erase(dir); // User has priority over Fallback
|
||||
}
|
||||
}
|
||||
void addIncDirFallback(const string& incdir) {
|
||||
const string& dir = V3Os::filenameCleanup(incdir);
|
||||
if (m_incDirUserSet.find(dir)
|
||||
== m_incDirUserSet.end()) { // User has priority over Fallback
|
||||
if (!m_incDirUsers.exists(dir)) { // User has priority over Fallback
|
||||
const auto itFoundPair = m_incDirFallbackSet.insert(dir);
|
||||
if (itFoundPair.second) m_incDirFallbacks.push_back(dir);
|
||||
}
|
||||
|
|
@ -106,10 +103,7 @@ public:
|
|||
m_langExts[addext] = lc;
|
||||
}
|
||||
|
||||
void addLibExtV(const string& libext) {
|
||||
const auto itFoundPair = m_libExtVSet.insert(libext);
|
||||
if (itFoundPair.second) m_libExtVs.push_back(libext);
|
||||
}
|
||||
void addLibExtV(const string& libext) { m_libExtVs.insert(libext); }
|
||||
V3OptionsImp() = default;
|
||||
~V3OptionsImp() = default;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Broken.h"
|
||||
#include "V3Container.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
#include "V3FunctionTraits.h"
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Broken.h"
|
||||
#include "V3Container.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
#include "V3FunctionTraits.h"
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ class PremitVisitor final : public VNVisitor {
|
|||
// Keep as local temporary.
|
||||
const std::string name = "__Vtemp_" + std::to_string(++m_tmpVarCnt);
|
||||
varp = new AstVar{flp, VVarType::STMTTEMP, name, nodep->dtypep()};
|
||||
varp->funcLocal(true);
|
||||
varp->noReset(true);
|
||||
m_cfuncp->addVarsp(varp);
|
||||
++m_temporaryVarsCreated;
|
||||
|
||||
|
|
|
|||
|
|
@ -1906,12 +1906,14 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
// Only hard constraints are currently supported
|
||||
// Emit as soft or hard constraint per IEEE 1800-2017 18.5.13
|
||||
const VCMethod method
|
||||
= nodep->isSoft() ? VCMethod::RANDOMIZER_SOFT : VCMethod::RANDOMIZER_HARD;
|
||||
AstCMethodHard* const callp = new AstCMethodHard{
|
||||
nodep->fileline(),
|
||||
new AstVarRef{nodep->fileline(), VN_AS(m_genp->user2p(), NodeModule), m_genp,
|
||||
VAccess::READWRITE},
|
||||
VCMethod::RANDOMIZER_HARD, nodep->exprp()->unlinkFrBack()};
|
||||
method, nodep->exprp()->unlinkFrBack()};
|
||||
callp->dtypeSetVoid();
|
||||
// Pass filename, lineno, and source as separate arguments
|
||||
// This allows EmitC to call protect() on filename, similar to VL_STOP
|
||||
|
|
@ -2178,6 +2180,7 @@ class CaptureVisitor final : public VNVisitor {
|
|||
std::map<const AstVar*, AstVar*> m_varCloneMap; // Map original var nodes to their clones
|
||||
std::set<AstNode*> m_ignore; // Nodes to ignore for capturing
|
||||
AstVar* m_thisp = nullptr; // Variable for outer context's object, if necessary
|
||||
bool m_staticContext = false; // True when capturing from a static function context
|
||||
|
||||
// METHODS
|
||||
|
||||
|
|
@ -2250,6 +2253,11 @@ class CaptureVisitor final : public VNVisitor {
|
|||
if (varIsParam) return CaptureMode::CAP_VALUE;
|
||||
// Static var in function (will not be inlined, because it's in class)
|
||||
if (callerIsClass && varIsFuncLocal) return CaptureMode::CAP_VALUE;
|
||||
// Static class members in static context don't need 'this' capture;
|
||||
// V3Class will move both the function and the member to __Vclpkg
|
||||
if (m_staticContext && callerIsClass && varIsFieldOfCaller
|
||||
&& varRefp->varp()->lifetime().isStatic())
|
||||
return CaptureMode::CAP_NO;
|
||||
if (callerIsClass && varIsFieldOfCaller) return CaptureMode::CAP_THIS;
|
||||
UASSERT_OBJ(!callerIsClass, varRefp, "Invalid reference?");
|
||||
return CaptureMode::CAP_VALUE;
|
||||
|
|
@ -2370,10 +2378,12 @@ class CaptureVisitor final : public VNVisitor {
|
|||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
explicit CaptureVisitor(AstNode* const nodep, AstNodeModule* callerp, AstClass* const targetp)
|
||||
explicit CaptureVisitor(AstNode* const nodep, AstNodeModule* callerp, AstClass* const targetp,
|
||||
bool staticContext = false)
|
||||
: m_argsp{nullptr}
|
||||
, m_callerp{callerp}
|
||||
, m_targetp{targetp} {
|
||||
, m_targetp{targetp}
|
||||
, m_staticContext{staticContext} {
|
||||
iterateAndNextNull(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -3945,9 +3955,16 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
if (nodep->classOrPackagep() && nodep->classOrPackagep()->name() == "std") {
|
||||
// Handle std::randomize; create wrapper function that calls basicStdRandomization on
|
||||
// each varref argument, then transform nodep to call that wrapper
|
||||
const bool inStaticContext = m_ftaskp && m_ftaskp->isStatic();
|
||||
AstVar* const stdrand = createStdRandomGenerator(m_modp);
|
||||
AstFunc* const randomizeFuncp = V3Randomize::newRandomizeStdFunc(
|
||||
m_memberMap, m_modp, m_inlineUniqueStdName.get(nodep));
|
||||
// When called from a static function, mark helper and stdrand as static
|
||||
// so V3Class moves them to __Vclpkg alongside the calling function
|
||||
if (inStaticContext) {
|
||||
stdrand->lifetime(VLifetime::STATIC_EXPLICIT);
|
||||
randomizeFuncp->isStatic(true);
|
||||
}
|
||||
randomizeFuncp->addStmtsp(
|
||||
new AstAssign{nodep->fileline(),
|
||||
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var),
|
||||
|
|
@ -4003,7 +4020,8 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
}
|
||||
if (withp) {
|
||||
FileLine* const fl = nodep->fileline();
|
||||
withCapturep = std::make_unique<CaptureVisitor>(withp->exprp(), m_modp, nullptr);
|
||||
withCapturep = std::make_unique<CaptureVisitor>(withp->exprp(), m_modp, nullptr,
|
||||
inStaticContext);
|
||||
withCapturep->addFunctionArguments(randomizeFuncp);
|
||||
// Clear old constraints and variables for std::randomize with clause
|
||||
if (stdrand) {
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ class ScopeVisitor final : public VNVisitor {
|
|||
clonep = nodep->cloneTree(false);
|
||||
}
|
||||
nodep->user2p(clonep);
|
||||
clonep->user2p(clonep); // For recursive self-references after cloneTree
|
||||
m_scopep->addBlocksp(clonep);
|
||||
// We iterate under the *clone*
|
||||
iterateChildren(clonep);
|
||||
|
|
|
|||
|
|
@ -226,15 +226,37 @@ static void warnNoSplit(const AstVar* varp, const AstNode* wherep, const char* r
|
|||
// Split Unpacked Variables
|
||||
// Replacement policy:
|
||||
// AstArraySel -> Just replace with the AstVarRef for the split variable
|
||||
// AstVarRef -> Create a temporary variable and refer the variable
|
||||
// AstSliceSel -> Create a temporary variable and refer the variable
|
||||
// AstVarRef -> Create a temporary variable and refer to the variable
|
||||
// AstSliceSel -> Create a temporary variable and refer to the variable
|
||||
|
||||
// Compare AstNode* to get deterministic ordering when showing messages.
|
||||
// Track order-of-encounter for nodes, so we are stable, versus comparing node pointers
|
||||
// (fileline may be the same across multiple nodes, so is insufficient)
|
||||
class SplitNodeOrder final {
|
||||
// NODE STATE
|
||||
// AstNode::user4() -> uint64_t. Order the node is in the tree
|
||||
const VNUser4InUse m_user4InUse;
|
||||
|
||||
public:
|
||||
static uint64_t nextId() {
|
||||
static uint64_t s_sequence = 0;
|
||||
return ++s_sequence;
|
||||
}
|
||||
static uint64_t nodeOrder(const AstNode* const nodep) {
|
||||
AstNode* const ncnodep = const_cast<AstNode*>(nodep);
|
||||
const uint64_t id = ncnodep->user4();
|
||||
if (VL_LIKELY(id)) return id;
|
||||
ncnodep->user4(nextId());
|
||||
return ncnodep->user4();
|
||||
}
|
||||
};
|
||||
|
||||
// Compare AstNode* to get deterministic ordering
|
||||
struct AstNodeComparator final {
|
||||
bool operator()(const AstNode* ap, const AstNode* bp) const {
|
||||
// First consider lines, as makes messages to user more obvious
|
||||
const int lineComp = ap->fileline()->operatorCompare(*bp->fileline());
|
||||
if (lineComp != 0) return lineComp < 0;
|
||||
return ap < bp;
|
||||
return SplitNodeOrder::nodeOrder(ap) < SplitNodeOrder::nodeOrder(bp);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -247,6 +269,7 @@ class UnpackRef final {
|
|||
const int m_lsb; // for SliceSel
|
||||
const VAccess m_access;
|
||||
const bool m_ftask; // true if the reference is in function/task. false if in module.
|
||||
|
||||
public:
|
||||
UnpackRef(AstNode* stmtp, AstVarRef* nodep, bool ftask)
|
||||
: m_contextp{stmtp}
|
||||
|
|
@ -587,12 +610,12 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
AstVarRef* createTempVar(AstNode* context, AstNode* nodep, AstUnpackArrayDType* dtypep,
|
||||
AstVarRef* createTempVar(AstNode* contextp, AstNode* nodep, AstUnpackArrayDType* dtypep,
|
||||
const std::string& name_prefix, std::vector<AstVar*>& vars,
|
||||
int start_idx, bool lvalue, bool /*ftask*/) {
|
||||
FileLine* const fl = nodep->fileline();
|
||||
const std::string name = m_tempNames.get(nodep) + "__" + name_prefix;
|
||||
AstNodeAssign* const assignp = VN_CAST(context, NodeAssign);
|
||||
AstNodeAssign* const assignp = VN_CAST(contextp, NodeAssign);
|
||||
if (assignp) {
|
||||
// "always_comb a = b;" to "always_comb begin a = b; end" so that local
|
||||
// variable can be added.
|
||||
|
|
@ -604,7 +627,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
<< " is created lsb:" << dtypep->lo() << " msb:" << dtypep->hi());
|
||||
// Use AstAssign if true, otherwise AstAssignW
|
||||
const bool use_simple_assign
|
||||
= (context && VN_IS(context, NodeFTaskRef)) || (assignp && VN_IS(assignp, Assign));
|
||||
= (contextp && VN_IS(contextp, NodeFTaskRef)) || (assignp && VN_IS(assignp, Assign));
|
||||
|
||||
for (int i = 0; i < dtypep->elementsConst(); ++i) {
|
||||
AstNodeExpr* lhsp
|
||||
|
|
@ -618,11 +641,11 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||
AstAssign* const ap = new AstAssign{fl, lhsp, rhsp};
|
||||
if (lvalue) {
|
||||
// If varp is LHS, this assignment must appear after the original
|
||||
// assignment(context).
|
||||
context->addNextHere(ap);
|
||||
// assignment(contextp).
|
||||
contextp->addNextHere(ap);
|
||||
} else {
|
||||
// If varp is RHS, this assignment comes just before the original assignment
|
||||
context->addHereThisAsNext(ap);
|
||||
contextp->addHereThisAsNext(ap);
|
||||
}
|
||||
UASSERT_OBJ(!m_contextp, m_contextp, "must be null");
|
||||
setContextAndIterate(ap, refp);
|
||||
|
|
@ -1364,6 +1387,7 @@ const char* SplitVarImpl::cannotSplitPackedVarReason(const AstVar* varp) {
|
|||
|
||||
void V3SplitVar::splitVariable(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
SplitNodeOrder order;
|
||||
SplitVarRefs refs;
|
||||
{
|
||||
const SplitUnpackedVarVisitor visitor{nodep};
|
||||
|
|
|
|||
|
|
@ -1856,7 +1856,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp,
|
|||
if (!makeChanges) return tconnects;
|
||||
|
||||
// Connect missing ones
|
||||
std::set<const AstVar*> argWrap; // Which ports are defaulted, forcing arg wrapper creation
|
||||
VInsertionSet<const AstVar*> argWrap; // Which ports are defaulted; need arg wrapper creation
|
||||
for (int i = 0; i < tpinnum; ++i) {
|
||||
AstVar* const portp = tconnects[i].first;
|
||||
if (!tconnects[i].second || !tconnects[i].second->exprp()) {
|
||||
|
|
@ -1882,7 +1882,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp,
|
|||
if (statep) {
|
||||
portp->pinNum(i + 1); // Make sure correct, will use to build name
|
||||
UINFO(9, "taskConnects arg wrapper needed " << portp->valuep());
|
||||
argWrap.emplace(portp);
|
||||
argWrap.insert(portp);
|
||||
} else { // statep = nullptr, called too late or otherwise to handle args
|
||||
// Problem otherwise is we might have a varref, task
|
||||
// call, or something else that only makes sense in the
|
||||
|
|
@ -1956,7 +1956,8 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp,
|
|||
}
|
||||
|
||||
void V3Task::taskConnectWrap(AstNodeFTaskRef* nodep, const V3TaskConnects& tconnects,
|
||||
V3TaskConnectState* statep, const std::set<const AstVar*>& argWrap) {
|
||||
V3TaskConnectState* statep,
|
||||
const VInsertionSet<const AstVar*>& argWrap) {
|
||||
statep->setDidWrap();
|
||||
// Make wrapper name such that is same iff same args are defaulted
|
||||
std::string newname = nodep->name() + "__Vtcwrap";
|
||||
|
|
@ -1973,7 +1974,7 @@ void V3Task::taskConnectWrap(AstNodeFTaskRef* nodep, const V3TaskConnects& tconn
|
|||
for (const auto& tconnect : tconnects) {
|
||||
const AstVar* const portp = tconnect.first;
|
||||
AstArg* const argp = tconnect.second;
|
||||
if (argWrap.find(portp) != argWrap.end()) { // Removed arg
|
||||
if (argWrap.exists(portp)) { // Removed arg
|
||||
statep->pushDeletep(argp->unlinkFrBack());
|
||||
}
|
||||
}
|
||||
|
|
@ -1985,7 +1986,7 @@ void V3Task::taskConnectWrap(AstNodeFTaskRef* nodep, const V3TaskConnects& tconn
|
|||
|
||||
AstNodeFTask* V3Task::taskConnectWrapNew(AstNodeFTask* taskp, const string& newname,
|
||||
const V3TaskConnects& tconnects,
|
||||
const std::set<const AstVar*>& argWrap) {
|
||||
const VInsertionSet<const AstVar*>& argWrap) {
|
||||
std::map<const AstVar*, AstVar*> oldNewVars; // Old -> new var mappings
|
||||
|
||||
AstNodeFTask* const newTaskp = taskp->cloneType(newname);
|
||||
|
|
@ -2019,7 +2020,7 @@ AstNodeFTask* V3Task::taskConnectWrapNew(AstNodeFTask* taskp, const string& newn
|
|||
for (const auto& tconnect : tconnects) {
|
||||
AstVar* const portp = tconnect.first;
|
||||
AstVar* newPortp;
|
||||
if (argWrap.find(portp) == argWrap.end()) { // Not removed arg
|
||||
if (!argWrap.exists(portp)) { // Not removed arg
|
||||
newPortp = new AstVar{portp->fileline(), portp->varType(), portp->name(), portp};
|
||||
newPortp->propagateWrapAttrFrom(portp);
|
||||
newPortp->funcLocal(true);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Container.h"
|
||||
#include "V3Error.h"
|
||||
|
||||
#include <utility>
|
||||
|
|
@ -58,10 +59,10 @@ public:
|
|||
bool makeChanges = true) VL_MT_DISABLED;
|
||||
static void taskConnectWrap(AstNodeFTaskRef* nodep, const V3TaskConnects& tconnects,
|
||||
V3TaskConnectState* statep,
|
||||
const std::set<const AstVar*>& argWrap) VL_MT_DISABLED;
|
||||
static AstNodeFTask* taskConnectWrapNew(AstNodeFTask* taskp, const string& newname,
|
||||
const V3TaskConnects& tconnects,
|
||||
const std::set<const AstVar*>& argWrap) VL_MT_DISABLED;
|
||||
const VInsertionSet<const AstVar*>& argWrap) VL_MT_DISABLED;
|
||||
static AstNodeFTask*
|
||||
taskConnectWrapNew(AstNodeFTask* taskp, const string& newname, const V3TaskConnects& tconnects,
|
||||
const VInsertionSet<const AstVar*>& argWrap) VL_MT_DISABLED;
|
||||
static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix,
|
||||
const string& toSuffix,
|
||||
const string& frPrefix = "") VL_MT_DISABLED;
|
||||
|
|
|
|||
|
|
@ -285,13 +285,9 @@ static void process() {
|
|||
}
|
||||
|
||||
if (!v3Global.opt.serializeOnly()) {
|
||||
// Lift expressions out of statements. Currently disabled for line and
|
||||
// expression coverage, as otherwise later V3Split would further split
|
||||
// combinational always blocks and alter counts (that needs to be fixed in V3Split)
|
||||
if (v3Global.opt.fLiftExpr() //
|
||||
&& !v3Global.opt.coverageLine() && !v3Global.opt.coverageExpr()) {
|
||||
V3LiftExpr::liftExprAll(v3Global.rootp());
|
||||
}
|
||||
// Lift expressions out of statements.
|
||||
if (v3Global.opt.fLiftExpr()) V3LiftExpr::liftExprAll(v3Global.rootp());
|
||||
|
||||
// Move assignments from X into MODULE temps.
|
||||
// (Before flattening, so each new X variable is shared between all scopes of that
|
||||
// module.)
|
||||
|
|
|
|||
|
|
@ -449,12 +449,12 @@
|
|||
logic unsigned [15:0] b;
|
||||
} pstruct;
|
||||
|
||||
000021 function logic func_side_effect;
|
||||
+000021 point: type=line comment=block hier=top.t.cond1
|
||||
000021 $display("SIDE EFFECT");
|
||||
+000021 point: type=line comment=block hier=top.t.cond1
|
||||
000021 return 1;
|
||||
+000021 point: type=line comment=block hier=top.t.cond1
|
||||
%000001 function logic func_side_effect;
|
||||
-000001 point: type=line comment=block hier=top.t.cond1
|
||||
%000001 $display("SIDE EFFECT");
|
||||
-000001 point: type=line comment=block hier=top.t.cond1
|
||||
%000001 return 1;
|
||||
-000001 point: type=line comment=block hier=top.t.cond1
|
||||
endfunction
|
||||
|
||||
000010 function arr_t get_arr;
|
||||
|
|
@ -465,14 +465,14 @@
|
|||
+000010 point: type=line comment=block hier=top.t.cond1
|
||||
endfunction
|
||||
|
||||
~000031 assign a = (cyc == 0) ? clk : 1'bz;
|
||||
~000011 assign a = (cyc == 0) ? clk : 1'bz;
|
||||
-000000 point: type=branch comment=cond_then hier=top.t.cond1
|
||||
+000031 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
+000011 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
~000028 assign b = (cyc == 1) ? clk : 0;
|
||||
-000003 point: type=branch comment=cond_then hier=top.t.cond1
|
||||
+000028 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
~000021 assign c = func_side_effect() ? clk : 0;
|
||||
+000021 point: type=branch comment=cond_then hier=top.t.cond1
|
||||
%000001 assign c = func_side_effect() ? clk : 0;
|
||||
-000001 point: type=branch comment=cond_then hier=top.t.cond1
|
||||
-000000 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
000010 always @(posedge clk) begin
|
||||
+000010 point: type=line comment=block hier=top.t.cond1
|
||||
|
|
@ -500,9 +500,9 @@
|
|||
assign m = tab[clk ? 3 : 4];
|
||||
|
||||
for (genvar i = 0; i < 2; i++) begin
|
||||
000011 assign g = clk ? 1 : 0;
|
||||
+000010 point: type=branch comment=cond_then hier=top.t.cond1
|
||||
+000011 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
000022 assign g = clk ? 1 : 0;
|
||||
+000020 point: type=branch comment=cond_then hier=top.t.cond1
|
||||
+000022 point: type=branch comment=cond_else hier=top.t.cond1
|
||||
end
|
||||
|
||||
000011 always begin
|
||||
|
|
|
|||
|
|
@ -150,20 +150,20 @@ DA:304,1
|
|||
DA:305,20
|
||||
DA:306,20
|
||||
DA:315,1
|
||||
DA:323,21
|
||||
DA:324,21
|
||||
DA:325,21
|
||||
DA:323,1
|
||||
DA:324,1
|
||||
DA:325,1
|
||||
DA:328,10
|
||||
DA:329,10
|
||||
DA:330,10
|
||||
DA:333,31
|
||||
DA:333,11
|
||||
BRDA:333,0,0,0
|
||||
BRDA:333,0,1,31
|
||||
BRDA:333,0,1,11
|
||||
DA:334,28
|
||||
BRDA:334,0,0,3
|
||||
BRDA:334,0,1,28
|
||||
DA:335,21
|
||||
BRDA:335,0,0,21
|
||||
DA:335,1
|
||||
BRDA:335,0,0,1
|
||||
BRDA:335,0,1,0
|
||||
DA:336,10
|
||||
DA:337,10
|
||||
|
|
@ -182,9 +182,9 @@ BRDA:340,0,3,5
|
|||
DA:343,11
|
||||
BRDA:343,0,0,11
|
||||
BRDA:343,0,1,0
|
||||
DA:349,11
|
||||
BRDA:349,0,0,10
|
||||
BRDA:349,0,1,11
|
||||
DA:349,22
|
||||
BRDA:349,0,0,20
|
||||
BRDA:349,0,1,22
|
||||
DA:352,11
|
||||
DA:353,10
|
||||
BRDA:353,0,0,0
|
||||
|
|
@ -218,5 +218,5 @@ DA:374,9
|
|||
BRDA:374,0,0,1
|
||||
BRDA:374,0,1,9
|
||||
BRF:83
|
||||
BRH:33
|
||||
BRH:32
|
||||
end_of_record
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -26,6 +26,5 @@ test.run(cmd=[
|
|||
],
|
||||
verilator_run=True)
|
||||
|
||||
test.files_identical(test.obj_dir + "/annotated/t_cover_line.v", "t/t_cover_line.out")
|
||||
test.vcd_identical(test.trace_filename, test.golden_filename)
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 jalcim
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Recursive constant function defined at file scope ($unit).
|
||||
// Without the V3Scope.cpp fix, this triggers:
|
||||
// %Error: Internal Error: V3Scope.cpp: No clone for package function
|
||||
|
||||
function automatic integer gate_depth;
|
||||
input integer way;
|
||||
integer d1, d2, sc, n1, n2;
|
||||
begin
|
||||
if (way <= 1) gate_depth = 0;
|
||||
else if (way <= 4) gate_depth = 1;
|
||||
else begin
|
||||
sc = $clog2(way);
|
||||
n1 = 1 << (sc - 1);
|
||||
n2 = way - n1;
|
||||
d1 = gate_depth(n1);
|
||||
d2 = gate_depth(n2);
|
||||
gate_depth = ((d1 > d2) ? d1 : d2) + 1;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
module t;
|
||||
localparam D5 = gate_depth(5);
|
||||
localparam D8 = gate_depth(8);
|
||||
|
||||
initial begin
|
||||
if (D5 !== 2) $stop;
|
||||
if (D8 !== 2) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
]},
|
||||
{"type":"CFUNC","name":"_eval_initial__TOP","addr":"(QB)","loc":"d,11:8,11:9","slow":true,"scopep":"(Z)","argsp": [],
|
||||
"varsp": [
|
||||
{"type":"VAR","name":"__Vtemp_1","addr":"(RB)","loc":"d,49:120,49:121","dtypep":"(SB)","origName":"__Vtemp_1","verilogName":"__Vtemp_1","direction":"NONE","lifetime":"NONE","varType":"STMTTEMP","dtypeName":"string","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
{"type":"VAR","name":"__Vtemp_1","addr":"(RB)","loc":"d,49:120,49:121","dtypep":"(SB)","origName":"__Vtemp_1","verilogName":"__Vtemp_1","direction":"NONE","noReset":true,"isFuncLocal":true,"lifetime":"NONE","varType":"STMTTEMP","dtypeName":"string","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
],
|
||||
"stmtsp": [
|
||||
{"type":"ASSIGN","name":"","addr":"(TB)","loc":"d,32:9,32:10","dtypep":"(UB)",
|
||||
|
|
@ -868,9 +868,9 @@
|
|||
"lhsp": [
|
||||
{"type":"VARREF","name":"__Vdly__t.e","addr":"(XN)","loc":"d,24:9,24:10","dtypep":"(M)","access":"WR","varp":"(UN)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}
|
||||
],"timingControlp": []},
|
||||
{"type":"VAR","name":"__Vtemp_1","addr":"(YN)","loc":"d,70:123,70:124","dtypep":"(SB)","origName":"__Vtemp_1","verilogName":"__Vtemp_1","direction":"NONE","lifetime":"NONE","varType":"STMTTEMP","dtypeName":"string","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"VAR","name":"__Vtemp_2","addr":"(ZN)","loc":"d,80:123,80:124","dtypep":"(SB)","origName":"__Vtemp_2","verilogName":"__Vtemp_2","direction":"NONE","lifetime":"NONE","varType":"STMTTEMP","dtypeName":"string","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"VAR","name":"__Vtemp_3","addr":"(AO)","loc":"d,90:123,90:124","dtypep":"(SB)","origName":"__Vtemp_3","verilogName":"__Vtemp_3","direction":"NONE","lifetime":"NONE","varType":"STMTTEMP","dtypeName":"string","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
{"type":"VAR","name":"__Vtemp_1","addr":"(YN)","loc":"d,70:123,70:124","dtypep":"(SB)","origName":"__Vtemp_1","verilogName":"__Vtemp_1","direction":"NONE","noReset":true,"isFuncLocal":true,"lifetime":"NONE","varType":"STMTTEMP","dtypeName":"string","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"VAR","name":"__Vtemp_2","addr":"(ZN)","loc":"d,80:123,80:124","dtypep":"(SB)","origName":"__Vtemp_2","verilogName":"__Vtemp_2","direction":"NONE","noReset":true,"isFuncLocal":true,"lifetime":"NONE","varType":"STMTTEMP","dtypeName":"string","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"VAR","name":"__Vtemp_3","addr":"(AO)","loc":"d,90:123,90:124","dtypep":"(SB)","origName":"__Vtemp_3","verilogName":"__Vtemp_3","direction":"NONE","noReset":true,"isFuncLocal":true,"lifetime":"NONE","varType":"STMTTEMP","dtypeName":"string","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
],
|
||||
"stmtsp": [
|
||||
{"type":"ASSIGN","name":"","addr":"(BO)","loc":"d,23:17,23:20","dtypep":"(S)",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
if not test.have_solver:
|
||||
test.skip("No constraint solver installed")
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test soft constraint solving per IEEE 1800-2017 section 18.5.13
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
// Case 1: Only soft, no hard -- soft should be satisfied
|
||||
class Case1;
|
||||
rand int x;
|
||||
constraint c_soft { soft x == 5; }
|
||||
endclass
|
||||
|
||||
// Case 2: Two soft on same var -- last-wins (c_b declared after c_a)
|
||||
class Case2;
|
||||
rand int x;
|
||||
constraint c_a { soft x == 5; }
|
||||
constraint c_b { soft x == 10; }
|
||||
endclass
|
||||
|
||||
// Case 3: Soft on different vars -- both should be satisfied
|
||||
class Case3;
|
||||
rand int x;
|
||||
rand int y;
|
||||
constraint c_x { soft x == 7; }
|
||||
constraint c_y { soft y == 3; }
|
||||
endclass
|
||||
|
||||
// Case 4: Soft range partially covered by hard -- SAT at intersection
|
||||
class Case4;
|
||||
rand int x;
|
||||
constraint c_soft { soft x inside {[1:10]}; }
|
||||
constraint c_hard { x inside {[5:15]}; }
|
||||
endclass
|
||||
|
||||
// Case 5: Soft completely overridden by hard -- hard wins
|
||||
class Case5;
|
||||
rand int x;
|
||||
constraint c_soft { soft x == 5; }
|
||||
constraint c_hard { x > 10; }
|
||||
endclass
|
||||
|
||||
module t;
|
||||
Case1 c1;
|
||||
Case2 c2;
|
||||
Case3 c3;
|
||||
Case4 c4;
|
||||
Case5 c5;
|
||||
int rand_ok;
|
||||
|
||||
initial begin
|
||||
c1 = new;
|
||||
c2 = new;
|
||||
c3 = new;
|
||||
c4 = new;
|
||||
c5 = new;
|
||||
|
||||
repeat (20) begin
|
||||
// Case 1: only soft, no hard -- soft satisfied
|
||||
rand_ok = c1.randomize();
|
||||
`checkd(rand_ok, 1)
|
||||
`checkd(c1.x, 5)
|
||||
|
||||
// Case 2: two soft on same var -- last-wins
|
||||
rand_ok = c2.randomize();
|
||||
`checkd(rand_ok, 1)
|
||||
`checkd(c2.x, 10)
|
||||
|
||||
// Case 3: soft on different vars -- both satisfied
|
||||
rand_ok = c3.randomize();
|
||||
`checkd(rand_ok, 1)
|
||||
`checkd(c3.x, 7)
|
||||
`checkd(c3.y, 3)
|
||||
|
||||
// Case 4: soft range partially covered by hard -- intersection [5:10]
|
||||
rand_ok = c4.randomize();
|
||||
`checkd(rand_ok, 1)
|
||||
`check_range(c4.x, 5, 10)
|
||||
|
||||
// Case 5: soft completely overridden by hard -- hard wins
|
||||
rand_ok = c5.randomize();
|
||||
`checkd(rand_ok, 1)
|
||||
if (c5.x <= 10) begin
|
||||
$write("%%Error: %s:%0d: x=%0d should be > 10\n", `__FILE__, `__LINE__, c5.x);
|
||||
`stop;
|
||||
end
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
if not test.have_solver:
|
||||
test.skip("No constraint solver installed")
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test std::randomize() called from a static function referencing static
|
||||
// class members in the 'with' clause.
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
|
||||
typedef enum bit [3:0] {
|
||||
INSTR_ADD = 0,
|
||||
INSTR_SUB = 1,
|
||||
INSTR_MUL = 2,
|
||||
INSTR_AND = 4
|
||||
} instr_name_t;
|
||||
|
||||
class instr_base;
|
||||
static instr_name_t allowed_instrs[$];
|
||||
|
||||
static function void init();
|
||||
allowed_instrs.push_back(INSTR_ADD);
|
||||
allowed_instrs.push_back(INSTR_SUB);
|
||||
allowed_instrs.push_back(INSTR_MUL);
|
||||
allowed_instrs.push_back(INSTR_AND);
|
||||
endfunction
|
||||
|
||||
static function instr_name_t get_rand_instr();
|
||||
instr_name_t name;
|
||||
int ok;
|
||||
ok = std::randomize(name) with {
|
||||
name inside {allowed_instrs};
|
||||
};
|
||||
`checkd(ok, 1);
|
||||
return name;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
initial begin
|
||||
instr_name_t result;
|
||||
|
||||
instr_base::init();
|
||||
|
||||
repeat (20) begin
|
||||
result = instr_base::get_rand_instr();
|
||||
`checkd(result == INSTR_ADD || result == INSTR_SUB
|
||||
|| result == INSTR_MUL || result == INSTR_AND, 1);
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue