mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Merge from master for release.
This commit is contained in:
@@ -63,6 +63,8 @@ ForEachMacros:
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '"V3Pch.*\.h"'
|
||||
Priority: -2 # Precompiled headers
|
||||
- Regex: '"(config_build|verilated_config|verilatedos)\.h"'
|
||||
Priority: -1 # Sepecials before main header
|
||||
- Regex: '(<|")verilated.*'
|
||||
@@ -112,6 +114,9 @@ SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 0
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
|
||||
@@ -23,6 +23,10 @@ defaults:
|
||||
shell: bash
|
||||
working-directory: repo
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
@@ -33,7 +37,8 @@ jobs:
|
||||
compiler:
|
||||
- { cc: clang, cxx: clang++ }
|
||||
- { cc: gcc, cxx: g++ }
|
||||
m32: [0, 1]
|
||||
# m32 1 is deprecated, not here to speed up regressions
|
||||
m32: [0]
|
||||
exclude:
|
||||
# Build pull requests only with ubuntu-22.04 and without m32
|
||||
# - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
|
||||
@@ -58,7 +63,7 @@ jobs:
|
||||
CC: ${{ matrix.compiler.cc }}
|
||||
CXX: ${{ matrix.compiler.cxx }}
|
||||
CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}
|
||||
CCACHE_MAXSIZE: 250M # Per build matrix entry (2000M in total)
|
||||
CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
|
||||
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz
|
||||
steps:
|
||||
|
||||
@@ -103,7 +108,7 @@ jobs:
|
||||
compiler:
|
||||
- { cc: clang, cxx: clang++ }
|
||||
- { cc: gcc, cxx: g++ }
|
||||
m32: [0, 1]
|
||||
m32: [0]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1]
|
||||
exclude:
|
||||
# Build pull requests only with ubuntu-22.04 and without m32
|
||||
@@ -131,7 +136,7 @@ jobs:
|
||||
CC: ${{ matrix.compiler.cc }}
|
||||
CXX: ${{ matrix.compiler.cxx }}
|
||||
CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}-${{ matrix.suite }}
|
||||
CCACHE_MAXSIZE: 64M # Per build matrix entry (2160M in total)
|
||||
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
|
||||
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz
|
||||
steps:
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# DESCRIPTION: Github actions config
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
name: lint
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
CI_COMMIT: ${{ github.sha }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: repo
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
lint-py:
|
||||
runs-on: ubuntu-22.04
|
||||
name: Lint Python
|
||||
env:
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
CI_M32: 0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
# We use specific version numbers, otherwise a Python package
|
||||
# update may add a warning and break our build
|
||||
- name: Install packages for lint
|
||||
run: sudo pip3 install pylint==3.0.2 ruff==0.1.3 clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||
|
||||
- name: Configure
|
||||
run: autoconf && ./configure --enable-longtests --enable-ccwarn
|
||||
|
||||
- name: Lint
|
||||
run: make -k lint-py
|
||||
@@ -22,6 +22,10 @@ defaults:
|
||||
run:
|
||||
working-directory: repo
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
windows:
|
||||
|
||||
@@ -43,3 +43,4 @@ verilator-config-version.cmake
|
||||
/.vscode/
|
||||
/.idea/
|
||||
/cmake-build-*/
|
||||
/test_regress/snapshot/
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
||||
project(Verilator
|
||||
VERSION 5.016
|
||||
VERSION 5.018
|
||||
HOMEPAGE_URL https://verilator.org
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
@@ -8,6 +8,82 @@ The changes in each Verilator version are described below. The
|
||||
contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
Verilator 5.018 2023-10-30
|
||||
==========================
|
||||
|
||||
**Major:**
|
||||
|
||||
* Support compilation with precompiled headers with Make and GCC or CLang.
|
||||
* Change include of systemc instead of systemc.h (#4622) (#4623). [Chih-Mao Chen]
|
||||
This may require that SystemC programs add 'using namespace sc_core', 'using namespace sc_dt'.
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Add SIDEEFFECT warning on mishandled side effect cases.
|
||||
* Add trace() API even when Verilated without --trace (#4462). [phelter]
|
||||
* Add warning on interface instantiation without parens (#4094). [Gökçe Aydos]
|
||||
* Add sv_vpi_user.h from IEEE 1800-2017 Annex M (#4606). [Marlon James]
|
||||
* Support 'disable fork' (#4125) (#4569). [Aleksander Kiryk, Antmicro Ltd.]
|
||||
* Support 'wait fork' (#4586). [Aleksander Kiryk, Antmicro Ltd.]
|
||||
* Support 'randc' (#4349).
|
||||
* Support assigning events (#4403). [Krzysztof Boroński]
|
||||
* Support resizing function call inout arguments (#4467).
|
||||
* Support NBAs in non-inlined functions/tasks (#4496) (#4572). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support converting parameters inside modules to localparams (#4511). [Anthony Donlon]
|
||||
* Support concatenation of unpacked arrays (#4558). [Yutetsu TAKATSUKASA]
|
||||
* Support Clang 16 (#4592). [Mariusz Glebocki]
|
||||
* Support VPI variables of real and string data types (#4594). [Marlon James]
|
||||
* Support making VL_LOCK_SPINS configurable (#4599). [Geza Lore]
|
||||
* Change code --stats output (#4597). [Geza Lore]
|
||||
* Change --prof-exec infrastructure and report (#4602). [Geza Lore]
|
||||
* Change lint_off to not propagate upwards to files including where the lint_off is.
|
||||
* Optimize empty expression statements (#4544).
|
||||
* Optimize trace internals (#4610) (#4612). [Geza Lore]
|
||||
* Optimize internal performance issues (#4638). [Geza Lore]
|
||||
* Fix conversion of impure logical expressions to bit expressions (#487 partial) (#4437). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix enum functions in localparams (#3999). [Andrew Nolte]
|
||||
* Fix passing arguments by reference (#3385 partial) (#4489). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix multithreading handling to separate by code units that use/never use it (#4228). [Mariusz Glebocki, Antmicro Ltd.]
|
||||
* Fix usage of annotation options (#4486) (#4504). [Michal Czyz]
|
||||
* Fix detecting local vars in nested forks (#4493) (#4506). [Kamil Rakoczy]
|
||||
* Fix handling input file path separator (#4515) (#4516). [Anthony Donlon]
|
||||
* Fix mis-support for parameterized UDPs (#4518). [Anthony Donlon]
|
||||
* Fix constant conversion of $realtobits, $bitstoreal (#4522). [Andrew Nolte]
|
||||
* Fix conversion of integers in $display '%e' (#4528). [muzafferkal]
|
||||
* Fix non-inlined interface tracing (#3984) (#4530). [Todd Strader]
|
||||
* Fix stream operations with operands of struct type (#4531) (#4532). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix 'this' in a constructor (#4533). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix stream shift operator of 32 bits (#4536). [Julien Faucher]
|
||||
* Fix object destruction after a copy constructor (#4540) (#4541). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix inlining of real functions miscasting (#4543). [Andrew Nolte]
|
||||
* Fix broken link error for enum references (#4551). [Anthony Donlon]
|
||||
* Fix logical expressions with class objects - caching in v3Const (#4552). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix using functions/tasks following class definition inside module (#4553). [Anthony Donlon]
|
||||
* Fix large constant buffer overflow (#4556). [Varun Koyyalagunta]
|
||||
* Fix instance arrays connecting to array of structs (#4557). [raphmaster]
|
||||
* Fix error message for invalid parameter overrides (#4559). [Anthony Donlon]
|
||||
* Fix shift to remove operation side effects (#4563).
|
||||
* Fix compile warning on unused member function variable (#4567).
|
||||
* Fix method narrowing conversion compiler error (#4568).
|
||||
* Fix interface comparison (#4570). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix dynamic triggers for named events (#4571). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix dictionaries with keys of class types (#4576). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix to not remap local assign intervals in forks (#4583). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix display optimization ignoring side effects (#4585).
|
||||
* Fix PLI/DPI user defined system task/function grammar (#4587) (#4588). [Quentin Corradi]
|
||||
* Fix fault on empty clocking block (#4593). [Alex Mykyta]
|
||||
* Fix creating implicit nets for inputs of gate primitives (#4603). [Geza Lore]
|
||||
* Fix try_put method of unbounded mailbox (#4608). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix stable name generation in V3Fork (#4615) (#4624). [Krzysztof Boroński]
|
||||
* Fix virtual methods (#4616). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix insertion at queue end (#4619). [Krzysztof Boroński]
|
||||
* Fix rand fields of reference types (#4627). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix dynamic casts of null values (#4631). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix signals read via virtual interfaces being misoptimized (#4645). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix handling of static keyword in methods (#4649). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix preprocessor to show `line 2 on resumed file.
|
||||
|
||||
|
||||
Verilator 5.016 2023-09-16
|
||||
==========================
|
||||
|
||||
|
||||
+12
-2
@@ -173,6 +173,10 @@ smoke-test: all_nomsg
|
||||
test_regress: all_nomsg
|
||||
$(MAKE) -C test_regress
|
||||
|
||||
.PHONY: test-snap test-diff
|
||||
test-snap test-diff:
|
||||
$(MAKE) -C test_regress $@
|
||||
|
||||
examples: all_nomsg
|
||||
for p in $(EXAMPLES) ; do \
|
||||
$(MAKE) -C $$p VERILATOR_ROOT=`pwd` || exit 10; \
|
||||
@@ -430,9 +434,15 @@ PYLINT_FLAGS = --score=n --disable=R0801
|
||||
RUFF = ruff
|
||||
RUFF_FLAGS = check --ignore=E402,E501,E701
|
||||
|
||||
# "make -k" so can see all tool result errors
|
||||
lint-py:
|
||||
-$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS)
|
||||
-$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
|
||||
$(MAKE) -k lint-py-pylint lint-py-ruff
|
||||
|
||||
lint-py-pylint:
|
||||
$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS)
|
||||
|
||||
lint-py-ruff:
|
||||
$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
|
||||
|
||||
format-pl-exec:
|
||||
-chmod a+x test_regress/t/*.pl
|
||||
|
||||
+1
-1
@@ -150,7 +150,7 @@ the terms of either the GNU Lesser General Public License Version 3 or the
|
||||
Perl Artistic License Version 2.0. See the documentation for more details.
|
||||
|
||||
.. _CHIPS Alliance: https://chipsalliance.org
|
||||
.. _Icarus Verilog: http://iverilog.icarus.com
|
||||
.. _Icarus Verilog: https://steveicarus.github.io/iverilog
|
||||
.. _Linux Foundation: https://www.linuxfoundation.org
|
||||
.. |Logo| image:: https://www.veripool.org/img/verilator_256_200_min.png
|
||||
.. |verilator multithreaded performance| image:: https://www.veripool.org/img/verilator_multithreaded_performance_bg-min.png
|
||||
|
||||
+339
-276
@@ -1,33 +1,32 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,C0114,C0116,C0209,C0301,R0914,R0912,R0915,W0511,eval-used
|
||||
# pylint: disable=C0103,C0114,C0116,C0209,C0301,R0914,R0912,R0915,W0511,W0603,eval-used
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
import bisect
|
||||
import collections
|
||||
import math
|
||||
import re
|
||||
import statistics
|
||||
# from pprint import pprint
|
||||
|
||||
Threads = collections.defaultdict(lambda: collections.defaultdict(lambda: {}))
|
||||
Mtasks = collections.defaultdict(lambda: {})
|
||||
Evals = collections.defaultdict(lambda: {})
|
||||
EvalLoops = collections.defaultdict(lambda: {})
|
||||
Sections = []
|
||||
LongestVcdStrValueLength = 0
|
||||
Threads = collections.defaultdict(lambda: []) # List of records per thread id
|
||||
Mtasks = collections.defaultdict(lambda: {'elapsed': 0, 'end': 0})
|
||||
Cpus = collections.defaultdict(lambda: {'mtask_time': 0})
|
||||
Global = {
|
||||
'args': {},
|
||||
'cpuinfo': collections.defaultdict(lambda: {}),
|
||||
'rdtsc_cycle_time': 0,
|
||||
'stats': {}
|
||||
}
|
||||
ElapsedTime = None # total elapsed time
|
||||
ExecGraphTime = 0 # total elapsed time excuting an exec graph
|
||||
ExecGraphIntervals = [] # list of (start, end) pairs
|
||||
|
||||
######################################################################
|
||||
|
||||
|
||||
def process(filename):
|
||||
read_data(filename)
|
||||
report()
|
||||
|
||||
|
||||
def read_data(filename):
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
|
||||
@@ -39,14 +38,17 @@ def read_data(filename):
|
||||
re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*')
|
||||
re_arg2 = re.compile(r'VLPROF arg\s+(\S+)\s+([0-9.]*)\s*$')
|
||||
re_stat = re.compile(r'VLPROF stat\s+(\S+)\s+([0-9.]+)')
|
||||
re_time = re.compile(r'rdtsc time = (\d+) ticks')
|
||||
re_proc_cpu = re.compile(r'VLPROFPROC processor\s*:\s*(\d+)\s*$')
|
||||
re_proc_dat = re.compile(r'VLPROFPROC ([a-z_ ]+)\s*:\s*(.*)$')
|
||||
cpu = None
|
||||
thread = None
|
||||
execGraphStart = None
|
||||
|
||||
lastEvalBeginTick = None
|
||||
lastEvalLoopBeginTick = None
|
||||
global LongestVcdStrValueLength
|
||||
global ExecGraphTime
|
||||
|
||||
SectionStack = []
|
||||
mTaskThread = {}
|
||||
|
||||
for line in fh:
|
||||
recordMatch = re_record.match(line)
|
||||
@@ -54,29 +56,31 @@ def read_data(filename):
|
||||
kind, tick, payload = recordMatch.groups()
|
||||
tick = int(tick)
|
||||
payload = payload.strip()
|
||||
if kind == "EVAL_BEGIN":
|
||||
Evals[tick]['start'] = tick
|
||||
lastEvalBeginTick = tick
|
||||
elif kind == "EVAL_END":
|
||||
Evals[lastEvalBeginTick]['end'] = tick
|
||||
lastEvalBeginTick = None
|
||||
elif kind == "EVAL_LOOP_BEGIN":
|
||||
EvalLoops[tick]['start'] = tick
|
||||
lastEvalLoopBeginTick = tick
|
||||
elif kind == "EVAL_LOOP_END":
|
||||
EvalLoops[lastEvalLoopBeginTick]['end'] = tick
|
||||
lastEvalLoopBeginTick = None
|
||||
if kind == "SECTION_PUSH":
|
||||
LongestVcdStrValueLength = max(LongestVcdStrValueLength,
|
||||
len(payload))
|
||||
SectionStack.append(payload)
|
||||
Sections.append((tick, tuple(SectionStack)))
|
||||
elif kind == "SECTION_POP":
|
||||
assert SectionStack, "SECTION_POP without SECTION_PUSH"
|
||||
SectionStack.pop()
|
||||
Sections.append((tick, tuple(SectionStack)))
|
||||
elif kind == "MTASK_BEGIN":
|
||||
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(
|
||||
payload).groups()
|
||||
mtask = int(mtask)
|
||||
predict_start = int(predict_start)
|
||||
ecpu = int(ecpu)
|
||||
Threads[thread][tick]['mtask'] = mtask
|
||||
Threads[thread][tick]['predict_start'] = predict_start
|
||||
Threads[thread][tick]['cpu'] = ecpu
|
||||
if 'elapsed' not in Mtasks[mtask]:
|
||||
Mtasks[mtask] = {'end': 0, 'elapsed': 0}
|
||||
mTaskThread[mtask] = thread
|
||||
records = Threads[thread]
|
||||
assert not records or records[-1]['start'] <= records[-1][
|
||||
'end'] <= tick
|
||||
records.append({
|
||||
'start': tick,
|
||||
'mtask': mtask,
|
||||
'predict_start': predict_start,
|
||||
'cpu': ecpu
|
||||
})
|
||||
Mtasks[mtask]['begin'] = tick
|
||||
Mtasks[mtask]['thread'] = thread
|
||||
Mtasks[mtask]['predict_start'] = predict_start
|
||||
@@ -86,11 +90,18 @@ def read_data(filename):
|
||||
mtask = int(mtask)
|
||||
predict_cost = int(predict_cost)
|
||||
begin = Mtasks[mtask]['begin']
|
||||
Threads[thread][begin]['end'] = tick
|
||||
Threads[thread][begin]['predict_cost'] = predict_cost
|
||||
record = Threads[mTaskThread[mtask]][-1]
|
||||
record['end'] = tick
|
||||
record['predict_cost'] = predict_cost
|
||||
Mtasks[mtask]['elapsed'] += tick - begin
|
||||
Mtasks[mtask]['predict_cost'] = predict_cost
|
||||
Mtasks[mtask]['end'] = max(Mtasks[mtask]['end'], tick)
|
||||
elif kind == "EXEC_GRAPH_BEGIN":
|
||||
execGraphStart = tick
|
||||
elif kind == "EXEC_GRAPH_END":
|
||||
ExecGraphTime += tick - execGraphStart
|
||||
ExecGraphIntervals.append((execGraphStart, tick))
|
||||
execGraphStart = None
|
||||
elif Args.debug:
|
||||
print("-Unknown execution trace record: %s" % line)
|
||||
elif re_thread.match(line):
|
||||
@@ -109,7 +120,7 @@ def read_data(filename):
|
||||
elif re_proc_cpu.match(line):
|
||||
match = re_proc_cpu.match(line)
|
||||
cpu = int(match.group(1))
|
||||
elif cpu and re_proc_dat.match(line):
|
||||
elif cpu is not None and re_proc_dat.match(line):
|
||||
match = re_proc_dat.match(line)
|
||||
term = match.group(1)
|
||||
value = match.group(2)
|
||||
@@ -121,11 +132,6 @@ def read_data(filename):
|
||||
pass
|
||||
elif Args.debug:
|
||||
print("-Unk: %s" % line)
|
||||
# TODO -- this is parsing text printed by a client.
|
||||
# Really, verilator proper should generate this
|
||||
# if it's useful...
|
||||
if re_time.match(line):
|
||||
Global['rdtsc_cycle_time'] = re_time.group(1)
|
||||
|
||||
|
||||
def re_match_result(regexp, line, result_to):
|
||||
@@ -144,125 +150,33 @@ def report():
|
||||
plus = "+" if re.match(r'^\+', arg) else " "
|
||||
print(" %s%s%s" % (arg, plus, Global['args'][arg]))
|
||||
|
||||
for records in Threads.values():
|
||||
for record in records:
|
||||
cpu = record['cpu']
|
||||
elapsed = record['end'] - record['start']
|
||||
Cpus[cpu]['mtask_time'] += elapsed
|
||||
|
||||
global ElapsedTime
|
||||
ElapsedTime = int(Global['stats']['ticks'])
|
||||
nthreads = int(Global['stats']['threads'])
|
||||
Global['cpus'] = {}
|
||||
for thread in Threads:
|
||||
# Make potentially multiple characters per column
|
||||
for start in Threads[thread]:
|
||||
if not Threads[thread][start]:
|
||||
continue
|
||||
cpu = Threads[thread][start]['cpu']
|
||||
elapsed = Threads[thread][start]['end'] - start
|
||||
if cpu not in Global['cpus']:
|
||||
Global['cpus'][cpu] = {'cpu_time': 0}
|
||||
Global['cpus'][cpu]['cpu_time'] += elapsed
|
||||
ncpus = max(len(Cpus), 1)
|
||||
|
||||
measured_mt_mtask_time = 0
|
||||
predict_mt_mtask_time = 0
|
||||
long_mtask_time = 0
|
||||
measured_last_end = 0
|
||||
predict_last_end = 0
|
||||
for mtask in Mtasks:
|
||||
measured_mt_mtask_time += Mtasks[mtask]['elapsed']
|
||||
predict_mt_mtask_time += Mtasks[mtask]['predict_cost']
|
||||
measured_last_end = max(measured_last_end, Mtasks[mtask]['end'])
|
||||
predict_last_end = max(
|
||||
predict_last_end,
|
||||
Mtasks[mtask]['predict_start'] + Mtasks[mtask]['predict_cost'])
|
||||
long_mtask_time = max(long_mtask_time, Mtasks[mtask]['elapsed'])
|
||||
Global['measured_last_end'] = measured_last_end
|
||||
Global['predict_last_end'] = predict_last_end
|
||||
|
||||
# If we know cycle time in the same (rdtsc) units,
|
||||
# this will give us an actual utilization number,
|
||||
# (how effectively we keep the cores busy.)
|
||||
#
|
||||
# It also gives us a number we can compare against
|
||||
# serial mode, to estimate the overhead of data sharing,
|
||||
# which will show up in the total elapsed time. (Overhead
|
||||
# of synchronization and scheduling should not.)
|
||||
print("\nAnalysis:")
|
||||
print(" Total threads = %d" % nthreads)
|
||||
print(" Total mtasks = %d" % len(Mtasks))
|
||||
ncpus = max(len(Global['cpus']), 1)
|
||||
print(" Total cpus used = %d" % ncpus)
|
||||
print(" Total yields = %d" %
|
||||
int(Global['stats'].get('yields', 0)))
|
||||
print(" Total evals = %d" % len(Evals))
|
||||
print(" Total eval loops = %d" % len(EvalLoops))
|
||||
if Mtasks:
|
||||
print(" Total eval time = %d rdtsc ticks" %
|
||||
Global['measured_last_end'])
|
||||
print(" Longest mtask time = %d rdtsc ticks" % long_mtask_time)
|
||||
print(" All-thread mtask time = %d rdtsc ticks" %
|
||||
measured_mt_mtask_time)
|
||||
long_efficiency = long_mtask_time / (Global.get(
|
||||
'measured_last_end', 1) or 1)
|
||||
print(" Longest-thread efficiency = %0.1f%%" %
|
||||
(long_efficiency * 100.0))
|
||||
mt_efficiency = measured_mt_mtask_time / (
|
||||
Global.get('measured_last_end', 1) * nthreads or 1)
|
||||
print(" All-thread efficiency = %0.1f%%" %
|
||||
(mt_efficiency * 100.0))
|
||||
print(" All-thread speedup = %0.1f" %
|
||||
(mt_efficiency * nthreads))
|
||||
if Global['rdtsc_cycle_time'] > 0:
|
||||
ut = measured_mt_mtask_time / Global['rdtsc_cycle_time']
|
||||
print("tot_mtask_cpu=" + measured_mt_mtask_time + " cyc=" +
|
||||
Global['rdtsc_cycle_time'] + " ut=" + ut)
|
||||
|
||||
predict_mt_efficiency = predict_mt_mtask_time / (
|
||||
Global.get('predict_last_end', 1) * nthreads or 1)
|
||||
print("\nPrediction (what Verilator used for scheduling):")
|
||||
print(" All-thread efficiency = %0.1f%%" %
|
||||
(predict_mt_efficiency * 100.0))
|
||||
print(" All-thread speedup = %0.1f" %
|
||||
(predict_mt_efficiency * nthreads))
|
||||
|
||||
p2e_ratios = []
|
||||
min_p2e = 1000000
|
||||
min_mtask = None
|
||||
max_p2e = -1000000
|
||||
max_mtask = None
|
||||
|
||||
for mtask in sorted(Mtasks.keys()):
|
||||
if Mtasks[mtask]['elapsed'] > 0:
|
||||
if Mtasks[mtask]['predict_cost'] == 0:
|
||||
Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below
|
||||
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
|
||||
Mtasks[mtask]['elapsed'])
|
||||
p2e_ratios.append(p2e_ratio)
|
||||
|
||||
if p2e_ratio > max_p2e:
|
||||
max_p2e = p2e_ratio
|
||||
max_mtask = mtask
|
||||
if p2e_ratio < min_p2e:
|
||||
min_p2e = p2e_ratio
|
||||
min_mtask = mtask
|
||||
|
||||
print("\nMTask statistics:")
|
||||
print(" min log(p2e) = %0.3f" % min_p2e, end="")
|
||||
print(" from mtask %d (predict %d," %
|
||||
(min_mtask, Mtasks[min_mtask]['predict_cost']),
|
||||
end="")
|
||||
print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
|
||||
print(" max log(p2e) = %0.3f" % max_p2e, end="")
|
||||
print(" from mtask %d (predict %d," %
|
||||
(max_mtask, Mtasks[max_mtask]['predict_cost']),
|
||||
end="")
|
||||
print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
|
||||
|
||||
stddev = statistics.pstdev(p2e_ratios)
|
||||
mean = statistics.mean(p2e_ratios)
|
||||
print(" mean = %0.3f" % mean)
|
||||
print(" stddev = %0.3f" % stddev)
|
||||
print(" e ^ stddev = %0.3f" % math.exp(stddev))
|
||||
print("\nSummary:")
|
||||
print(" Total elapsed time = {} rdtsc ticks".format(ElapsedTime))
|
||||
print(" Parallelized code = {:.2%} of elapsed time".format(
|
||||
ExecGraphTime / ElapsedTime))
|
||||
print(" Total threads = %d" % nthreads)
|
||||
print(" Total CPUs used = %d" % ncpus)
|
||||
print(" Total mtasks = %d" % len(Mtasks))
|
||||
print(" Total yields = %d" % int(Global['stats'].get('yields', 0)))
|
||||
|
||||
report_mtasks()
|
||||
report_cpus()
|
||||
report_sections()
|
||||
|
||||
if nthreads > ncpus:
|
||||
print()
|
||||
print("%%Warning: There were fewer CPUs (%d) then threads (%d)." %
|
||||
print("%%Warning: There were fewer CPUs (%d) than threads (%d)." %
|
||||
(ncpus, nthreads))
|
||||
print(" : See docs on use of numactl.")
|
||||
else:
|
||||
@@ -279,32 +193,130 @@ def report():
|
||||
print()
|
||||
|
||||
|
||||
def report_mtasks():
|
||||
if not Mtasks:
|
||||
return
|
||||
|
||||
nthreads = int(Global['stats']['threads'])
|
||||
|
||||
# If we know cycle time in the same (rdtsc) units,
|
||||
# this will give us an actual utilization number,
|
||||
# (how effectively we keep the cores busy.)
|
||||
#
|
||||
# It also gives us a number we can compare against
|
||||
# serial mode, to estimate the overhead of data sharing,
|
||||
# which will show up in the total elapsed time. (Overhead
|
||||
# of synchronization and scheduling should not.)
|
||||
total_mtask_time = 0
|
||||
thread_mtask_time = collections.defaultdict(lambda: 0)
|
||||
long_mtask_time = 0
|
||||
long_mtask = None
|
||||
predict_mtask_time = 0
|
||||
predict_elapsed = 0
|
||||
for mtaskId in Mtasks:
|
||||
record = Mtasks[mtaskId]
|
||||
predict_mtask_time += record['predict_cost']
|
||||
total_mtask_time += record['elapsed']
|
||||
thread_mtask_time[record['thread']] += record['elapsed']
|
||||
predict_end = record['predict_start'] + record['predict_cost']
|
||||
predict_elapsed = max(predict_elapsed, predict_end)
|
||||
if record['elapsed'] > long_mtask_time:
|
||||
long_mtask_time = record['elapsed']
|
||||
long_mtask = mtaskId
|
||||
Global['predict_last_end'] = predict_elapsed
|
||||
|
||||
serialTime = ElapsedTime - ExecGraphTime
|
||||
|
||||
def subReport(elapsed, work):
|
||||
print(" Thread utilization = {:7.2%}".format(work /
|
||||
(elapsed * nthreads)))
|
||||
print(" Speedup = {:6.3}x".format(work / elapsed))
|
||||
|
||||
print("\nParallelized code, measured:")
|
||||
subReport(ExecGraphTime, total_mtask_time)
|
||||
|
||||
print("\nParallelized code, predicted during static scheduling:")
|
||||
subReport(predict_elapsed, predict_mtask_time)
|
||||
|
||||
print("\nAll code, measured:")
|
||||
subReport(ElapsedTime, serialTime + total_mtask_time)
|
||||
|
||||
print("\nAll code, measured, scaled by predicted speedup:")
|
||||
expectedParallelSpeedup = predict_mtask_time / predict_elapsed
|
||||
scaledElapsed = serialTime + total_mtask_time / expectedParallelSpeedup
|
||||
subReport(scaledElapsed, serialTime + total_mtask_time)
|
||||
|
||||
p2e_ratios = []
|
||||
min_p2e = 1000000
|
||||
min_mtask = None
|
||||
max_p2e = -1000000
|
||||
max_mtask = None
|
||||
|
||||
for mtask in sorted(Mtasks.keys()):
|
||||
if Mtasks[mtask]['elapsed'] > 0:
|
||||
if Mtasks[mtask]['predict_cost'] == 0:
|
||||
Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below
|
||||
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
|
||||
Mtasks[mtask]['elapsed'])
|
||||
p2e_ratios.append(p2e_ratio)
|
||||
|
||||
if p2e_ratio > max_p2e:
|
||||
max_p2e = p2e_ratio
|
||||
max_mtask = mtask
|
||||
if p2e_ratio < min_p2e:
|
||||
min_p2e = p2e_ratio
|
||||
min_mtask = mtask
|
||||
|
||||
print("\nMTask statistics:")
|
||||
print(" Longest mtask id = {}".format(long_mtask))
|
||||
print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".
|
||||
format(long_mtask_time / ExecGraphTime))
|
||||
print(" min log(p2e) = %0.3f" % min_p2e, end="")
|
||||
|
||||
print(" from mtask %d (predict %d," %
|
||||
(min_mtask, Mtasks[min_mtask]['predict_cost']),
|
||||
end="")
|
||||
print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
|
||||
print(" max log(p2e) = %0.3f" % max_p2e, end="")
|
||||
print(" from mtask %d (predict %d," %
|
||||
(max_mtask, Mtasks[max_mtask]['predict_cost']),
|
||||
end="")
|
||||
print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
|
||||
|
||||
stddev = statistics.pstdev(p2e_ratios)
|
||||
mean = statistics.mean(p2e_ratios)
|
||||
print(" mean = %0.3f" % mean)
|
||||
print(" stddev = %0.3f" % stddev)
|
||||
print(" e ^ stddev = %0.3f" % math.exp(stddev))
|
||||
|
||||
|
||||
def report_cpus():
|
||||
print("\nCPUs:")
|
||||
print("\nCPU info:")
|
||||
|
||||
Global['cpu_sockets'] = collections.defaultdict(lambda: 0)
|
||||
Global['cpu_socket_cores'] = collections.defaultdict(lambda: 0)
|
||||
|
||||
for cpu in sorted(Global['cpus'].keys()):
|
||||
print(" cpu %d: " % cpu, end='')
|
||||
print("cpu_time=%d" % Global['cpus'][cpu]['cpu_time'], end='')
|
||||
|
||||
socket = None
|
||||
print(" Id | Time spent executing MTask | Socket | Core | Model")
|
||||
print(" | % of elapsed ticks / ticks | | |")
|
||||
print(" ====|============================|========|======|======")
|
||||
for cpu in sorted(Cpus):
|
||||
socket = ""
|
||||
core = ""
|
||||
model = ""
|
||||
if cpu in Global['cpuinfo']:
|
||||
cpuinfo = Global['cpuinfo'][cpu]
|
||||
if 'physical_id' in cpuinfo and 'core_id' in cpuinfo:
|
||||
socket = int(cpuinfo['physical_id'])
|
||||
socket = cpuinfo['physical_id']
|
||||
Global['cpu_sockets'][socket] += 1
|
||||
print(" socket=%d" % socket, end='')
|
||||
|
||||
core = int(cpuinfo['core_id'])
|
||||
Global['cpu_socket_cores'][str(socket) + "__" + str(core)] += 1
|
||||
print(" core=%d" % core, end='')
|
||||
core = cpuinfo['core_id']
|
||||
Global['cpu_socket_cores'][socket + "__" + core] += 1
|
||||
|
||||
if 'model_name' in cpuinfo:
|
||||
model = cpuinfo['model_name']
|
||||
print(" %s" % model, end='')
|
||||
print()
|
||||
|
||||
print(" {:3d} | {:7.2%} / {:16d} | {:>6s} | {:>4s} | {}".format(
|
||||
cpu, Cpus[cpu]['mtask_time'] / ElapsedTime,
|
||||
Cpus[cpu]['mtask_time'], socket, core, model))
|
||||
|
||||
if len(Global['cpu_sockets']) > 1:
|
||||
Global['cpu_sockets_warning'] = True
|
||||
@@ -313,25 +325,68 @@ def report_cpus():
|
||||
Global['cpu_socket_cores_warning'] = True
|
||||
|
||||
|
||||
def report_sections():
|
||||
if not Sections:
|
||||
return
|
||||
print("\nSection profile:")
|
||||
|
||||
totalTime = collections.defaultdict(lambda: 0)
|
||||
selfTime = collections.defaultdict(lambda: 0)
|
||||
|
||||
sectionTree = [0, {}, 1] # [selfTime, childTrees, numberOfTimesEntered]
|
||||
prevTime = 0
|
||||
prevStack = ()
|
||||
for time, stack in Sections:
|
||||
if len(stack) > len(prevStack):
|
||||
scope = sectionTree
|
||||
for item in stack:
|
||||
scope = scope[1].setdefault(item, [0, {}, 0])
|
||||
scope[2] += 1
|
||||
dt = time - prevTime
|
||||
scope = sectionTree
|
||||
for item in prevStack:
|
||||
scope = scope[1].setdefault(item, [0, {}, 0])
|
||||
scope[0] += dt
|
||||
|
||||
if prevStack:
|
||||
for name in prevStack:
|
||||
totalTime[name] += dt
|
||||
selfTime[prevStack[-1]] += dt
|
||||
prevTime = time
|
||||
prevStack = stack
|
||||
|
||||
def treeSum(tree):
|
||||
n = tree[0]
|
||||
for subTree in tree[1].values():
|
||||
n += treeSum(subTree)
|
||||
return n
|
||||
|
||||
# Make sure the tree sums to the elapsed time
|
||||
sectionTree[0] += ElapsedTime - treeSum(sectionTree)
|
||||
|
||||
def printTree(prefix, name, entries, tree):
|
||||
print(" {:7.2%} | {:7.2%} | {:8} | {:10.2f} | {}".format(
|
||||
treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2],
|
||||
tree[2] / entries, prefix + name))
|
||||
for k in sorted(tree[1], key=lambda _: -treeSum(tree[1][_])):
|
||||
printTree(prefix + " ", k, tree[2], tree[1][k])
|
||||
|
||||
print(" Total | Self | Total | Relative | Section")
|
||||
print(" time | time | entries | entries | name ")
|
||||
print("==========|=========|==========|============|========")
|
||||
printTree("", "*TOTAL*", 1, sectionTree)
|
||||
|
||||
|
||||
######################################################################
|
||||
|
||||
|
||||
def write_vcd(filename):
|
||||
print("Writing %s" % filename)
|
||||
with open(filename, "w", encoding="utf8") as fh:
|
||||
vcd = {
|
||||
'values':
|
||||
collections.defaultdict(lambda: {}), # {<time>}{<code>} = value
|
||||
'sigs': {
|
||||
'predicted_threads': {},
|
||||
'measured_threads': {},
|
||||
'cpus': {},
|
||||
'evals': {},
|
||||
'mtasks': {},
|
||||
'Stats': {}
|
||||
} # {<module>}{<sig}} = code
|
||||
}
|
||||
code = 0
|
||||
# dict of dicts of hierarchy elements/signal name -> (code, width)
|
||||
scopeSigs = {}
|
||||
# map from time -> code -> value
|
||||
values = collections.defaultdict(lambda: {})
|
||||
|
||||
parallelism = {
|
||||
'measured': collections.defaultdict(lambda: 0),
|
||||
@@ -340,132 +395,139 @@ def write_vcd(filename):
|
||||
parallelism['measured'][0] = 0
|
||||
parallelism['predicted'][0] = 0
|
||||
|
||||
# Measured graph
|
||||
for thread in sorted(Threads.keys()):
|
||||
sig = "thread%d_mtask" % thread
|
||||
if sig not in vcd['sigs']['measured_threads']:
|
||||
vcd['sigs']['measured_threads'][sig] = code
|
||||
code += 1
|
||||
mcode = vcd['sigs']['measured_threads'][sig]
|
||||
nextFreeCode = 0
|
||||
|
||||
for start in sorted(Threads[thread]):
|
||||
mtask = Threads[thread][start]['mtask']
|
||||
end = Threads[thread][start]['end']
|
||||
cpu = Threads[thread][start]['cpu']
|
||||
vcd['values'][start][mcode] = mtask
|
||||
vcd['values'][end][mcode] = None
|
||||
def getCode(width, *names):
|
||||
nonlocal nextFreeCode
|
||||
scope = scopeSigs
|
||||
*path, name = names
|
||||
for item in path:
|
||||
scope = scope.setdefault(item, {})
|
||||
code, oldWidth = scope.setdefault(name, (nextFreeCode, width))
|
||||
assert oldWidth == width
|
||||
if code == nextFreeCode:
|
||||
nextFreeCode += 1
|
||||
return code
|
||||
|
||||
def addValue(code, time, val):
|
||||
if isinstance(val, str):
|
||||
buf = ""
|
||||
for c in val:
|
||||
buf += bin(ord(c))[2:].rjust(8, "0")
|
||||
val = buf.ljust(LongestVcdStrValueLength * 8, "0")
|
||||
values[time][code] = val
|
||||
|
||||
# Measured graph
|
||||
for thread in sorted(Threads):
|
||||
mcode = getCode(32, 'measured', 't%d_mtask' % thread)
|
||||
for record in Threads[thread]:
|
||||
start = record['start']
|
||||
mtask = record['mtask']
|
||||
end = record['end']
|
||||
cpu = record['cpu']
|
||||
addValue(mcode, start, mtask)
|
||||
addValue(mcode, end, None)
|
||||
parallelism['measured'][start] += 1
|
||||
parallelism['measured'][end] -= 1
|
||||
|
||||
sig = "cpu%d_thread" % cpu
|
||||
if sig not in vcd['sigs']['cpus']:
|
||||
vcd['sigs']['cpus'][sig] = code
|
||||
code += 1
|
||||
ccode = vcd['sigs']['cpus'][sig]
|
||||
vcd['values'][start][ccode] = thread
|
||||
vcd['values'][end][ccode] = None
|
||||
code = getCode(32, 'measured', 'cpu%d_thread' % cpu)
|
||||
addValue(code, start, thread)
|
||||
addValue(code, end, None)
|
||||
|
||||
sig = "mtask%d_cpu" % mtask
|
||||
if sig not in vcd['sigs']['mtasks']:
|
||||
vcd['sigs']['mtasks'][sig] = code
|
||||
code += 1
|
||||
ccode = vcd['sigs']['mtasks'][sig]
|
||||
vcd['values'][start][ccode] = cpu
|
||||
vcd['values'][end][ccode] = None
|
||||
code = getCode(32, 'measured', 'cpu%d_mtask' % cpu)
|
||||
addValue(code, start, mtask)
|
||||
addValue(code, end, None)
|
||||
|
||||
# Eval graph
|
||||
vcd['sigs']['evals']["eval"] = code
|
||||
elcode = code
|
||||
code += 1
|
||||
n = 0
|
||||
for eval_start in Evals:
|
||||
eval_end = Evals[eval_start]['end']
|
||||
n += 1
|
||||
vcd['values'][eval_start][elcode] = n
|
||||
vcd['values'][eval_end][elcode] = None
|
||||
tStart = sorted(_['start'] for records in Threads.values()
|
||||
for _ in records)
|
||||
tEnd = sorted(_['end'] for records in Threads.values()
|
||||
for _ in records)
|
||||
|
||||
# Eval_loop graph
|
||||
vcd['sigs']['evals']["eval_loop"] = code
|
||||
elcode = code
|
||||
code += 1
|
||||
n = 0
|
||||
for eval_start in EvalLoops:
|
||||
eval_end = EvalLoops[eval_start]['end']
|
||||
n += 1
|
||||
vcd['values'][eval_start][elcode] = n
|
||||
vcd['values'][eval_end][elcode] = None
|
||||
# Predicted graph
|
||||
for start, end in ExecGraphIntervals:
|
||||
# Find the earliest MTask start after the start point, and the
|
||||
# latest MTask end before the end point, so we can scale to the
|
||||
# same range
|
||||
start = tStart[bisect.bisect_left(tStart, start)]
|
||||
end = tEnd[bisect.bisect_right(tEnd, end) - 1]
|
||||
# Compute scale so predicted graph is of same width as interval
|
||||
measured_scaling = (end - start) / Global['predict_last_end']
|
||||
# Predict mtasks that fill the time the execution occupied
|
||||
for mtask in Mtasks:
|
||||
thread = Mtasks[mtask]['thread']
|
||||
pred_scaled_start = start + int(
|
||||
Mtasks[mtask]['predict_start'] * measured_scaling)
|
||||
pred_scaled_end = start + int(
|
||||
(Mtasks[mtask]['predict_start'] +
|
||||
Mtasks[mtask]['predict_cost']) * measured_scaling)
|
||||
if pred_scaled_start == pred_scaled_end:
|
||||
continue
|
||||
|
||||
if Mtasks:
|
||||
# Predicted graph
|
||||
for eval_start in EvalLoops:
|
||||
eval_end = EvalLoops[eval_start]['end']
|
||||
# Compute scale so predicted graph is of same width as eval
|
||||
measured_scaling = (eval_end -
|
||||
eval_start) / Global['predict_last_end']
|
||||
# Predict mtasks that fill the time the eval occupied
|
||||
for mtask in Mtasks:
|
||||
thread = Mtasks[mtask]['thread']
|
||||
pred_scaled_start = eval_start + int(
|
||||
Mtasks[mtask]['predict_start'] * measured_scaling)
|
||||
pred_scaled_end = eval_start + int(
|
||||
(Mtasks[mtask]['predict_start'] +
|
||||
Mtasks[mtask]['predict_cost']) * measured_scaling)
|
||||
if pred_scaled_start == pred_scaled_end:
|
||||
continue
|
||||
mcode = getCode(32, 'predicted', 't%d_mtask' % thread)
|
||||
addValue(mcode, pred_scaled_start, mtask)
|
||||
addValue(mcode, pred_scaled_end, None)
|
||||
|
||||
sig = "predicted_thread%d_mtask" % thread
|
||||
if sig not in vcd['sigs']['predicted_threads']:
|
||||
vcd['sigs']['predicted_threads'][sig] = code
|
||||
code += 1
|
||||
mcode = vcd['sigs']['predicted_threads'][sig]
|
||||
parallelism['predicted'][pred_scaled_start] += 1
|
||||
parallelism['predicted'][pred_scaled_end] -= 1
|
||||
|
||||
vcd['values'][pred_scaled_start][mcode] = mtask
|
||||
vcd['values'][pred_scaled_end][mcode] = None
|
||||
# Parallelism graph
|
||||
for measpred in ('measured', 'predicted'):
|
||||
pcode = getCode(32, 'stats', '%s_parallelism' % measpred)
|
||||
value = 0
|
||||
for time in sorted(parallelism[measpred].keys()):
|
||||
value += parallelism[measpred][time]
|
||||
addValue(pcode, time, value)
|
||||
|
||||
parallelism['predicted'][pred_scaled_start] += 1
|
||||
parallelism['predicted'][pred_scaled_end] -= 1
|
||||
|
||||
# Parallelism graph
|
||||
for measpred in ('measured', 'predicted'):
|
||||
vcd['sigs']['Stats']["%s_parallelism" % measpred] = code
|
||||
pcode = code
|
||||
code += 1
|
||||
value = 0
|
||||
for time in sorted(parallelism[measpred].keys()):
|
||||
value += parallelism[measpred][time]
|
||||
vcd['values'][time][pcode] = value
|
||||
# Section graph
|
||||
if Sections:
|
||||
scode = getCode(LongestVcdStrValueLength * 8, "section", "trace")
|
||||
dcode = getCode(32, "section", "depth")
|
||||
for time, stack in Sections:
|
||||
addValue(scode, time, stack[-1] if stack else None)
|
||||
addValue(dcode, time, len(stack))
|
||||
|
||||
# Create output file
|
||||
fh.write("$version Generated by verilator_gantt $end\n")
|
||||
fh.write("$timescale 1ns $end\n")
|
||||
fh.write("\n")
|
||||
|
||||
all_codes = {}
|
||||
all_codes = set()
|
||||
|
||||
def writeScope(scope):
|
||||
assert isinstance(scope, dict)
|
||||
for key in sorted(scope):
|
||||
val = scope[key]
|
||||
if isinstance(val, dict):
|
||||
fh.write(" $scope module %s $end\n" % key)
|
||||
writeScope(val)
|
||||
fh.write(" $upscope $end\n")
|
||||
else:
|
||||
(code, width) = val
|
||||
all_codes.add(code)
|
||||
fh.write(" $var wire %d v%x %s [%d:0] $end\n" %
|
||||
(width, code, key, width - 1))
|
||||
|
||||
fh.write(" $scope module gantt $end\n")
|
||||
for module in sorted(vcd['sigs'].keys()):
|
||||
fh.write(" $scope module %s $end\n" % module)
|
||||
for sig in sorted(vcd['sigs'][module].keys()):
|
||||
code = vcd['sigs'][module][sig]
|
||||
fh.write(" $var wire 32 v%x %s [31:0] $end\n" % (code, sig))
|
||||
all_codes[code] = 1
|
||||
fh.write(" $upscope $end\n")
|
||||
writeScope(scopeSigs)
|
||||
fh.write(" $upscope $end\n")
|
||||
fh.write("$enddefinitions $end\n")
|
||||
fh.write("\n")
|
||||
|
||||
first = True
|
||||
for time in sorted(vcd['values']):
|
||||
for time in sorted(values):
|
||||
if first:
|
||||
first = False
|
||||
# Start with Z for any signals without time zero data
|
||||
for code in sorted(all_codes.keys()):
|
||||
if code not in vcd['values'][time]:
|
||||
vcd['values'][time][code] = None
|
||||
for code in sorted(all_codes):
|
||||
if code not in values[time]:
|
||||
addValue(code, time, None)
|
||||
fh.write("#%d\n" % time)
|
||||
for code in sorted(vcd['values'][time].keys()):
|
||||
value = vcd['values'][time][code]
|
||||
for code in sorted(values[time]):
|
||||
value = values[time][code]
|
||||
if value is None:
|
||||
fh.write("bz v%x\n" % code)
|
||||
elif isinstance(value, str):
|
||||
fh.write("b%s v%x\n" % (value, code))
|
||||
else:
|
||||
fh.write("b%s v%x\n" % (format(value, 'b'), code))
|
||||
|
||||
@@ -504,7 +566,8 @@ parser.add_argument('filename',
|
||||
|
||||
Args = parser.parse_args()
|
||||
|
||||
process(Args.filename)
|
||||
read_data(Args.filename)
|
||||
report()
|
||||
if not Args.no_vcd:
|
||||
write_vcd(Args.vcd)
|
||||
|
||||
|
||||
@@ -26,4 +26,5 @@ if git log --format=%B -n 1 "$COMMIT" | grep -q -i '\[CI\s\+ccache\s\+clear\]';
|
||||
fi
|
||||
|
||||
# Dump stats, then zero stats
|
||||
# 22.04: ccache -s -v -z
|
||||
ccache -s -z
|
||||
|
||||
@@ -49,6 +49,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
||||
./configure --enable-longtests --enable-ccwarn ${CI_M32:+--enable-m32}
|
||||
ccache -z
|
||||
"$MAKE" -j "$NPROC" -k
|
||||
# 22.04: ccache -s -v
|
||||
ccache -s
|
||||
if [ "$CI_OS_NAME" = "osx" ]; then
|
||||
file bin/verilator_bin
|
||||
@@ -180,6 +181,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||
fatal "Unknown test: $TESTS"
|
||||
;;
|
||||
esac
|
||||
# 22.04: ccache -s -v
|
||||
ccache -s
|
||||
|
||||
# Upload coverage data
|
||||
|
||||
+32
-9
@@ -10,7 +10,7 @@
|
||||
# Then 'make maintainer-dist'
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[5.016 2023-09-16],
|
||||
AC_INIT([Verilator],[5.018 2023-10-30],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
|
||||
@@ -24,6 +24,10 @@ AC_SUBST(PACKAGE_VERSION_NUMBER)
|
||||
AC_DEFINE_UNQUOTED([PACKAGE_VERSION_NUMBER_STRING],["$PACKAGE_VERSION_NUMBER"],[Package version as a number])
|
||||
VERILATOR_VERSION_INTEGER=`AS_ECHO("$PACKAGE_VERSION") | [sed 's/\([0-9]\)\.\([0-9][0-9][0-9]\) .*/\1\2000/g']`
|
||||
AC_SUBST(VERILATOR_VERSION_INTEGER)
|
||||
AC_DEFINE_UNQUOTED([PACKAGE_VERSION_STRING_CHAR],
|
||||
[static const char* const PACKAGE_STRING_UNUSED = "$PACKAGE_STRING";],
|
||||
[Package version as a number])
|
||||
AC_SUBST(PACKAGE_VERSION_STRING_CHAR)
|
||||
|
||||
# Ignore automake flags passed by Ubuntu builds
|
||||
AC_ARG_ENABLE([dependency-tracking],
|
||||
@@ -371,10 +375,9 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wthread-safety)
|
||||
AC_SUBST(CFG_CXXFLAGS_WEXTRA)
|
||||
|
||||
# Flags for coroutine support for dynamic scheduling
|
||||
_MY_CXX_CHECK_IFELSE(
|
||||
-fcoroutines-ts,
|
||||
[CFG_CXXFLAGS_COROUTINES="-fcoroutines-ts"],
|
||||
[CFG_CXXFLAGS_COROUTINES="-fcoroutines"])
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts -Wno-deprecated-experimental-coroutine)
|
||||
AC_SUBST(CFG_CXXFLAGS_COROUTINES)
|
||||
|
||||
# HAVE_COROUTINES
|
||||
@@ -442,14 +445,19 @@ m4_foreach([cflag],[
|
||||
[-mno-cet],
|
||||
[-Qunused-arguments],
|
||||
[-Wno-bool-operation],
|
||||
[-Wno-tautological-bitwise-compare],
|
||||
[-Wno-c++11-narrowing],
|
||||
[-Wno-constant-logical-operand],
|
||||
[-Wno-non-pod-varargs],
|
||||
[-Wno-overloaded-virtual],
|
||||
[-Wno-parentheses-equality],
|
||||
[-Wno-shadow],
|
||||
[-Wno-sign-compare],
|
||||
[-Wno-tautological-bitwise-compare],
|
||||
[-Wno-uninitialized],
|
||||
[-Wno-unused-but-set-parameter],
|
||||
[-Wno-unused-but-set-variable],
|
||||
[-Wno-unused-parameter],
|
||||
[-Wno-unused-variable],
|
||||
[-Wno-shadow]],[
|
||||
[-Wno-unused-variable]],[
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,cflag)
|
||||
# CMake will test what flags work itself, so pass all flags through to it
|
||||
CFG_CXX_FLAGS_CMAKE="$CFG_CXX_FLAGS_CMAKE cflag"
|
||||
@@ -559,6 +567,21 @@ Verilator requires a C++11 or newer compiler.]])
|
||||
fi
|
||||
AC_SUBST(CFG_CXXFLAGS_STD)
|
||||
|
||||
# Compiler precompiled header options (assumes either gcc or clang++)
|
||||
AC_MSG_CHECKING([for $CXX precompile header include option])
|
||||
if $CXX --help | grep include-pch >/dev/null 2>/dev/null ; then
|
||||
# clang
|
||||
CFG_CXXFLAGS_PCH_I=-include-pch
|
||||
CFG_GCH_IF_CLANG=.gch
|
||||
else
|
||||
# GCC
|
||||
CFG_CXXFLAGS_PCH_I=-include
|
||||
CFG_GCH_IF_CLANG=
|
||||
fi
|
||||
AC_MSG_RESULT($CFG_CXXFLAGS_PCH_I)
|
||||
AC_SUBST(CFG_CXXFLAGS_PCH_I)
|
||||
AC_SUBST(CFG_GCH_IF_CLANG)
|
||||
|
||||
# Checks for library functions.
|
||||
AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
|
||||
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
|
||||
@@ -573,7 +596,7 @@ ACO_SAVE_LIBS="$LIBS"
|
||||
LIBS="$LIBS -lsystemc"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([[#include <systemc.h>
|
||||
extern "C" int sc_main(int argc, char* argv[]) {}
|
||||
extern "C" int sc_main(int argc, char* argv[]) { return 0; }
|
||||
]],[[sc_version()]])],
|
||||
[_my_result=yes
|
||||
AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])],
|
||||
|
||||
@@ -19,6 +19,7 @@ Anthony Donlon
|
||||
Arkadiusz Kozdra
|
||||
Aylon Chaim Porat
|
||||
Cameron Kirk
|
||||
Chih-Mao Chen
|
||||
Chris Randall
|
||||
Chuxuan Wang
|
||||
Conor McCullough
|
||||
@@ -49,6 +50,7 @@ Glen Gibb
|
||||
Gökçe Aydos
|
||||
Graham Rushton
|
||||
Guokai Chen
|
||||
Gus Smith
|
||||
Gustav Svensk
|
||||
Harald Heckmann
|
||||
Hennadii Chernyshchyk
|
||||
@@ -57,6 +59,7 @@ Huang Rui
|
||||
Huanghuang Zhou
|
||||
HungMingWu
|
||||
HyungKi Jeong
|
||||
Ícaro Lima
|
||||
Ilya Barkov
|
||||
Iru Cai
|
||||
Ivan Vnučec
|
||||
@@ -88,6 +91,7 @@ Josh Redford
|
||||
Julian Daube
|
||||
Julie Schwartz
|
||||
Julien Margetts
|
||||
Justin Thiel
|
||||
Kaleb Barrett
|
||||
Kamil Rakoczy
|
||||
Kanad Kanhere
|
||||
@@ -114,6 +118,7 @@ Martin Stadler
|
||||
Matthew Ballance
|
||||
Michael Killough
|
||||
Michaël Lefebvre
|
||||
Michal Czyz
|
||||
Mike Popoloski
|
||||
Miodrag Milanović
|
||||
Mladen Slijepcevic
|
||||
@@ -134,6 +139,7 @@ Pierre-Henri Horrein
|
||||
Pieter Kapsenberg
|
||||
Piotr Binkowski
|
||||
Qingyao Sun
|
||||
Quentin Corradi
|
||||
Rafal Kapuscik
|
||||
Raynard Qiao
|
||||
Richard Myers
|
||||
@@ -179,5 +185,6 @@ Yuri Victorovich
|
||||
Yutetsu TAKATSUKASA
|
||||
Yves Mathieu
|
||||
Zhanglei Wang
|
||||
Zhou Shen
|
||||
Zixi Li
|
||||
أحمد المحمودي
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0201,R0903
|
||||
# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0903
|
||||
# -*- Python -*- See copyright, etc below
|
||||
######################################################################
|
||||
|
||||
|
||||
+1
-1
@@ -230,4 +230,4 @@ spelling_ignore_contributor_names = True
|
||||
|
||||
breathe_projects = {"verilated": "_build/doxygen/verilated/xml/"}
|
||||
breathe_default_project = "verilated"
|
||||
breathe_default_members = ('members')
|
||||
breathe_default_members = 'members'
|
||||
|
||||
@@ -7,6 +7,21 @@ Environment
|
||||
This section describes the environment variables used by Verilator and
|
||||
associated programs.
|
||||
|
||||
.. option:: AR
|
||||
|
||||
Optionally overrides the default :command:`ar` (archive) binary used by
|
||||
the Verilated makefiles. If AR is not set, the version found at
|
||||
configure time is used.
|
||||
|
||||
.. option:: CXX
|
||||
|
||||
Optionally overrides the default compiler binary used by the Verilated
|
||||
makefiles. If CXX is not set, the version found at configure time is
|
||||
used. Note the default flags passed to the compiler are determined at
|
||||
configuration time, so changing the CXX compiler version using this
|
||||
variable, as opposed to passing it at configuration time, may not give
|
||||
desired results.
|
||||
|
||||
.. option:: LD_LIBRARY_PATH
|
||||
|
||||
A generic Linux/OS variable specifying what directories have shared
|
||||
@@ -35,6 +50,12 @@ associated programs.
|
||||
those programs. If OBJCACHE is not set, and at configure time ccache
|
||||
was present, ccache will be used as a default.
|
||||
|
||||
.. option:: PYTHON3
|
||||
|
||||
Optionally overrides the default :command:`python3` binary used by the
|
||||
Verilated makefiles. If PYTHON3 is not set, the version found at
|
||||
configure time is used.
|
||||
|
||||
.. option:: SYSTEMC
|
||||
|
||||
Deprecated. Used only if :option:`SYSTEMC_INCLUDE` or
|
||||
|
||||
@@ -64,30 +64,59 @@ if there are multiple coverage points on a single line they will merge.
|
||||
The minimum coverage across all merged points will be used to report
|
||||
coverage of the line.
|
||||
|
||||
The first character of the line shows a summary of the coverage; this
|
||||
allows use of grep to filter the report. `%` indicates at least one point
|
||||
on the line was below the coverage limit. `+` indicates an
|
||||
:option:`--annotate-points` point was at or above the limit, and `-` that
|
||||
the point was below the limit.
|
||||
Coverage data is annotated at the beginning of the line and is formatted
|
||||
as a special character followed by the number of coverage hits. The special
|
||||
characters " ,%,+,-" indicate summary of the coverage, and allow use of grep
|
||||
to filter the report.
|
||||
|
||||
* " " (whitespace) indicates that all points on the line are above the coverage limit.
|
||||
* "%" indicates at least one point on the line was below the coverage limit.
|
||||
* "+" coverage point was at or above the limit. Only used with :option:`--annotate-points`.
|
||||
* "-" coverage point was below the limit. Only used with :option:`--annotate-points`.
|
||||
|
||||
.. code-block::
|
||||
|
||||
100000 input logic a; // Begins with whitespace, because
|
||||
// number of hits (100000) is above the limit.
|
||||
+100000 point: comment=a // Begins with +, because
|
||||
// number of hits (100000) is above the limit.
|
||||
%000000 input logic b; // Begins with %, because
|
||||
// number of hits (0) is below the limit.
|
||||
-000000 point: comment=b // Begins with -, because
|
||||
// number of hits (0) is below the limit.
|
||||
|
||||
.. option:: --annotate-all
|
||||
|
||||
Specifies all files should be shown. By default, only those source files
|
||||
with low coverage are written to the output directory.
|
||||
|
||||
This option should be used together with :option:`--annotate`.
|
||||
|
||||
.. option:: --annotate-min <count>
|
||||
|
||||
Specifies if the coverage point does not include the count number of
|
||||
coverage hits, then the coverage point will be considered above the
|
||||
threshold, and the coverage report will put a "%" to indicate the coverage
|
||||
is insufficient. Defaults to 10.
|
||||
Specifies the threshold (<count>) below which coverage point is considered
|
||||
sufficient. If the threshold is not exceeded, then the annotation will begin
|
||||
with a "%" symbol to indicate the coverage is insufficient.
|
||||
|
||||
The <count> threshold defaults to 10.
|
||||
|
||||
This option should be used together with :option:`--annotate`.
|
||||
|
||||
|
||||
.. option:: --annotate-points
|
||||
|
||||
Specifies all coverage points should be shown after each line of text. By
|
||||
default, only source lines are shown.
|
||||
|
||||
with low coverage are written to the output directory.
|
||||
.. code-block::
|
||||
|
||||
100000 input logic a, b, c;
|
||||
+100000 point: comment=a // These lines are only shown
|
||||
+200000 point: comment=b // with option --annotate-points
|
||||
+300000 point: comment=c // enabled.
|
||||
|
||||
|
||||
This option should be used together with :option:`--annotate`.
|
||||
|
||||
.. option:: --help
|
||||
|
||||
|
||||
@@ -30,15 +30,13 @@ Gantt Chart VCD Signals
|
||||
In waveforms, there are the following signals. In GTKWave, use "decimal"
|
||||
data format to remove the leading zeros and make the traces easier to read.
|
||||
|
||||
evals
|
||||
Increments each time when eval_step was measured to be active. This
|
||||
allow visualization of how much time eval_step was active.
|
||||
trace/section
|
||||
Shows the name of the current top of the execution section stack.
|
||||
Set GTKWave data format to "ASCII".
|
||||
|
||||
eval_loop
|
||||
Increments each time when the evaluation loop within eval_step was
|
||||
measured to be active. For best performance, there is only a single
|
||||
evaluation loop within each eval_step call; that is, the eval_loop
|
||||
waveform looks identical to the evals waveform.
|
||||
trace/depth
|
||||
Shows the depth of the execution section stack.
|
||||
Set GTKWave data format to "Analog".
|
||||
|
||||
measured_parallelism
|
||||
The number of mtasks active at this time, for best performance, this will
|
||||
|
||||
@@ -17,14 +17,21 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
.. option:: `__LINE__
|
||||
|
||||
The :option:`\`__LINE__` define expands to the current filename as a
|
||||
string, like C++'s __LINE__. This Verilator feature added in 2006 was
|
||||
incorporated into IEEE 1800-2009.
|
||||
The :option:`\`__LINE__` define expands to the current line number like
|
||||
C++'s __LINE__. This Verilator feature added in 2006 was incorporated
|
||||
into IEEE 1800-2009.
|
||||
|
||||
.. option:: `error [string]
|
||||
|
||||
This will report an error when encountered, like C++'s #error.
|
||||
|
||||
.. option:: `line
|
||||
|
||||
As a special case `\`line \`__LINE__ "filename"` allows setting the
|
||||
filename, without changing the line number. This is used for some
|
||||
internal tests, so that debugging can leave the line numbers correctly
|
||||
referring to the test file's line numbers.
|
||||
|
||||
.. option:: """ [string] """
|
||||
|
||||
A triple-quoted block specifies a string that may include newlines and
|
||||
|
||||
+18
-37
@@ -237,11 +237,9 @@ optimizations will be disabled around the latch.
|
||||
Structures and Unions
|
||||
---------------------
|
||||
|
||||
Presently Verilator only supports packed structs and packed unions. Rand
|
||||
and randc tags on members are ignored. All structures and unions are
|
||||
represented as a single vector, which means that generating one member of a
|
||||
structure from blocking, and another from non-blocking assignments is
|
||||
unsupported.
|
||||
All structures and unions are scheduled together, which means that
|
||||
generating one member of a structure from blocking, and another from
|
||||
non-blocking assignments is unsupported.
|
||||
|
||||
|
||||
.. _Unknown States:
|
||||
@@ -320,20 +318,6 @@ there will be considered a two-state variable that is read and written
|
||||
instead of a four-state variable.
|
||||
|
||||
|
||||
Functions & Tasks
|
||||
-----------------
|
||||
|
||||
All functions and tasks will be inlined (will not become functions in C.)
|
||||
The only support provided is simple statements in tasks (which may
|
||||
affect global variables).
|
||||
|
||||
Recursive functions and tasks are not supported. All inputs and outputs
|
||||
are automatic as if they had the Verilog 2001 "automatic" keyword
|
||||
prepended. (If you don't know what this means, Verilator will do what you
|
||||
probably expect, what C does. The default behavior of Verilog is
|
||||
different.)
|
||||
|
||||
|
||||
Gate Primitives
|
||||
---------------
|
||||
|
||||
@@ -383,24 +367,6 @@ Verilator does not support SEREs yet. All assertion and coverage
|
||||
statements must be simple expressions that complete in one cycle.
|
||||
|
||||
|
||||
Force statement
|
||||
---------------
|
||||
|
||||
Verilator supports the procedural `force` (and corresponding `release`)
|
||||
statement. However, the behavior of the `force` statement does not entirely
|
||||
comply with IEEE 1800. According to the standard,
|
||||
when a procedural statement of the form `force a = b;` is executed, the
|
||||
simulation should behave as if, from that point forwards, a continuous
|
||||
assignment `assign a = b;` has been added to override the drivers of `a`.
|
||||
More specifically: the value of `a` should be updated whenever the value of
|
||||
`b` changes, until a `release a;` statement is executed.
|
||||
Verilator instead evaluates the current value of `b` when the `force`
|
||||
statement is executed, and forces `a` to that value, without updating it
|
||||
until a new `force` or `release` statement is encountered that applies to
|
||||
`a`. This non-standard behavior is nevertheless consistent with some other
|
||||
simulators.
|
||||
|
||||
|
||||
Encrypted Verilog
|
||||
-----------------
|
||||
|
||||
@@ -471,6 +437,21 @@ disable
|
||||
provide loop break and continue functionality before SystemVerilog added
|
||||
the break and continue keywords.
|
||||
|
||||
force, release
|
||||
Verilator supports the procedural `force` (and corresponding `release`)
|
||||
statement. However, the behavior of the `force` statement does not
|
||||
entirely comply with IEEE 1800. According to the standard, when a
|
||||
procedural statement of the form `force a = b;` is executed, the
|
||||
simulation should behave as if, from that point forwards, a continuous
|
||||
assignment `assign a = b;` has been added to override the drivers of `a`.
|
||||
More specifically: the value of `a` should be updated whenever the value
|
||||
of `b` changes, until a `release a;` statement is executed. Verilator
|
||||
instead evaluates the current value of `b` when the `force` statement is
|
||||
executed, and forces `a` to that value, without updating it until a new
|
||||
`force` or `release` statement is encountered that applies to `a`. This
|
||||
non-standard behavior is nevertheless consistent with some other
|
||||
simulators.
|
||||
|
||||
inside
|
||||
Inside expressions may not include unpacked array traversal or $ as an
|
||||
upper bound. Case inside and case matches are also unsupported.
|
||||
|
||||
+60
-15
@@ -12,10 +12,18 @@ Disabling Warnings
|
||||
|
||||
Warnings may be disabled in multiple ways:
|
||||
|
||||
#. Disable the warning in the source code. When the warning is printed, it
|
||||
will include a warning code. Surround the offending line with a
|
||||
:code:`/*verilator&32;lint_off*/` and :code:`/*verilator&32;lint_on*/`
|
||||
metacomment pair:
|
||||
#. Disable the warning globally by invoking Verilator with the
|
||||
:code:`-Wno-{warning-code}` option.
|
||||
|
||||
Global disables should be avoided, as they removes all checking across
|
||||
the source files, and prevents other users from compiling the sources
|
||||
without knowing the magic set of disables needed to compile those
|
||||
sources successfully.
|
||||
|
||||
#. Disable the warning in the design source code. When the warning is
|
||||
printed, it will include a warning code. Surround the offending line
|
||||
with a :code:`/*verilator&32;lint_off*/` and
|
||||
:code:`/*verilator&32;lint_on*/` metacomment pair:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
@@ -23,6 +31,12 @@ Warnings may be disabled in multiple ways:
|
||||
if (`DEF_THAT_IS_EQ_ZERO <= 3) $stop;
|
||||
// verilator lint_on UNSIGNED
|
||||
|
||||
|
||||
A lint_off in the design source code will propagate down to any child
|
||||
files (files later included by the file with the lint_off), but will not
|
||||
propagate upwards to any parent file (file that included the file with
|
||||
the lint_off).
|
||||
|
||||
#. Disable the warning using :ref:`Configuration Files` with a
|
||||
:option:`lint_off` command. This is useful when a script suppresses
|
||||
warnings, and the Verilog source should not be changed. This method also
|
||||
@@ -32,12 +46,6 @@ Warnings may be disabled in multiple ways:
|
||||
|
||||
lint_off -rule UNSIGNED -file "*/example.v" -line 1
|
||||
|
||||
#. Disable the warning globally invoking Verilator with the
|
||||
:code:`-Wno-{warning-code}` option. This should be avoided, as it
|
||||
removes all checking across the designs, and prevents other users from
|
||||
compiling your code without knowing the magic set of disables needed to
|
||||
compile your design successfully.
|
||||
|
||||
|
||||
Error And Warning Format
|
||||
========================
|
||||
@@ -1166,7 +1174,7 @@ List Of Warnings
|
||||
|
||||
Warns that a feature requires a newer standard of Verilog or SystemVerilog
|
||||
than the one specified by the :vlopt:`--language` option. For example, unsized
|
||||
unbased literals (`'0`, `'1`, `'z`, `'x`) require 1800-2005 or later.
|
||||
unbased literals (`'0`, `'1`, `'z`, `'x`) require IEEE 1800-2005 or later.
|
||||
|
||||
To avoid this warning, use a Verilog or SystemVerilog standard that
|
||||
supports the feature. Alternatively, modify your code to use a different
|
||||
@@ -1360,7 +1368,10 @@ List Of Warnings
|
||||
|
||||
.. option:: RANDC
|
||||
|
||||
Warns that the :code:`randc` keyword is unsupported and being converted
|
||||
Historical, never issued since version 5.018, when :code:`randc` became
|
||||
fully supported.
|
||||
|
||||
Warned that the :code:`randc` keyword was unsupported and was converted
|
||||
to :code:`rand`.
|
||||
|
||||
|
||||
@@ -1503,6 +1514,39 @@ List Of Warnings
|
||||
modeled values, or DPI calls.
|
||||
|
||||
|
||||
.. option:: SIDEEFFECT
|
||||
|
||||
Warns that an expression has a side effect that might not properly be
|
||||
executed by Verilator.
|
||||
|
||||
This often represents a bug in Verilator, as opposed to a bad code
|
||||
construct, however the Verilog code can typically be changed to avoid
|
||||
the warning.
|
||||
|
||||
Faulty example:
|
||||
|
||||
.. code-block:: sv
|
||||
:linenos:
|
||||
:emphasize-lines: 1
|
||||
|
||||
x = y[a++];
|
||||
|
||||
This example warns because Verilator does not currently handle side
|
||||
effects inside array subscripts; the a++ may be executed multiple times.
|
||||
|
||||
Rewrite the code to avoid expression side effects, typically by using a
|
||||
temporary:
|
||||
|
||||
.. code-block:: sv
|
||||
:linenos:
|
||||
|
||||
temp = a++;
|
||||
x = y[temp];
|
||||
|
||||
Ignoring this warning may make Verilator simulations differ from other
|
||||
simulators.
|
||||
|
||||
|
||||
.. option:: SPLITVAR
|
||||
|
||||
Warns that a variable with a :option:`/*verilator&32;split_var*/`
|
||||
@@ -2043,17 +2087,18 @@ List Of Warnings
|
||||
|
||||
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_fixed.rst
|
||||
|
||||
|
||||
.. option:: WIDTHTRUNC
|
||||
|
||||
A more granular WIDTH warning, for when a value is truncated
|
||||
A more granular WIDTH warning, for when a value is truncated.
|
||||
|
||||
.. option:: WIDTHEXPAND
|
||||
|
||||
A more granular WIDTH warning, for when a value is zero expanded
|
||||
A more granular WIDTH warning, for when a value is zero expanded.
|
||||
|
||||
.. option:: WIDTHXZEXPAND
|
||||
|
||||
A more granular WIDTH warning, for when a value is X/Z expanded
|
||||
A more granular WIDTH warning, for when a value is X/Z expanded.
|
||||
|
||||
.. option:: WIDTHCONCAT
|
||||
|
||||
|
||||
+18
-5
@@ -1222,9 +1222,9 @@ There are three ways data is passed between visitor functions.
|
||||
|
||||
2. User attributes. Each ``AstNode`` (**Note.** The AST node, not the
|
||||
visitor) has five user attributes, which may be accessed as an
|
||||
integer using the ``user1()`` through ``user5()`` methods, or as a
|
||||
integer using the ``user1()`` through ``user4()`` methods, or as a
|
||||
pointer (of type ``AstNUser``) using the ``user1p()`` through
|
||||
``user5p()`` methods (a common technique lifted from graph traversal
|
||||
``user4p()`` methods (a common technique lifted from graph traversal
|
||||
packages).
|
||||
|
||||
A visitor first clears the one it wants to use by calling
|
||||
@@ -1400,7 +1400,7 @@ Controlling the Test Driver
|
||||
---------------------------
|
||||
|
||||
The test driver script `driver.pl` runs tests; see the `Test Driver`
|
||||
section. The individual test drivers are written in PERL; see `Test
|
||||
section. The individual test drivers are written in Perl; see `Test
|
||||
Language`.
|
||||
|
||||
|
||||
@@ -1432,7 +1432,7 @@ Developers will also want to call ./configure with two extra flags:
|
||||
disabled by default, as SystemC installation problems would otherwise
|
||||
falsely indicate a Verilator problem.
|
||||
|
||||
When enabling the long tests, some additional PERL modules are needed,
|
||||
When enabling the long tests, some additional Perl modules are needed,
|
||||
which you can install using cpan.
|
||||
|
||||
::
|
||||
@@ -1462,6 +1462,19 @@ There are some traps to avoid when running regression tests
|
||||
system-dependent, but on Fedora Linux it would require editing the
|
||||
``/etc/security/limits.conf`` file as root.
|
||||
|
||||
Diffing generated code after changes
|
||||
------------------------------------
|
||||
|
||||
When making a change in the code generation area that should not change the
|
||||
actual emitted code, it is useful to perform a diff to make sure the emitted
|
||||
code really did not change. To do this, the top level Makefile provides the
|
||||
*test-snap* and *test-diff* targets:
|
||||
|
||||
- Run the test suite with ``make test``
|
||||
- Take a snapshot with ``make test-snap``
|
||||
- Apply your changes
|
||||
- Run the test suite again with ``make test``
|
||||
- See the changes in the output with ``make test-diff``
|
||||
|
||||
Continuous Integration
|
||||
----------------------
|
||||
@@ -1640,7 +1653,7 @@ Source file and line
|
||||
file is ``a``, the 26th is ``z``, the 27th is ``aa``, and so on.
|
||||
|
||||
User pointers
|
||||
Shows the value of the node's user1p...user5p, if non-NULL.
|
||||
Shows the value of the node's user1p...user4p, if non-NULL.
|
||||
|
||||
Data type
|
||||
Many nodes have an explicit data type. "@dt=0x..." indicates the
|
||||
|
||||
@@ -35,11 +35,13 @@ Briquet
|
||||
Brownlee
|
||||
Buckenmaier
|
||||
Bybell
|
||||
CLang
|
||||
CMake
|
||||
Cai
|
||||
Cavium
|
||||
Cfuncs
|
||||
Chandan
|
||||
Chih
|
||||
Chitlesh
|
||||
Christophe
|
||||
Cochrane
|
||||
@@ -89,6 +91,7 @@ Engstrom
|
||||
Enzo
|
||||
Eugen
|
||||
Fabrizio
|
||||
Faucher
|
||||
Fekete
|
||||
Ferrandi
|
||||
Flachs
|
||||
@@ -230,6 +233,7 @@ Mong
|
||||
Muhlestein
|
||||
Multithreaded
|
||||
Multithreading
|
||||
Mykyta
|
||||
NOUNOPTFLAT
|
||||
NaN
|
||||
Nalbantis
|
||||
@@ -486,6 +490,7 @@ countbits
|
||||
countones
|
||||
cout
|
||||
cpp
|
||||
cppstyle
|
||||
cpu
|
||||
ctor
|
||||
ctrace
|
||||
@@ -520,6 +525,7 @@ doxygen
|
||||
dpiGetContext
|
||||
dpic
|
||||
dsvf
|
||||
dt
|
||||
dtor
|
||||
dumpall
|
||||
dumpfile
|
||||
@@ -721,6 +727,7 @@ multithreading
|
||||
musl
|
||||
mutexes
|
||||
mux
|
||||
muzafferkal
|
||||
myftptoyman
|
||||
mysignal
|
||||
namespace
|
||||
@@ -759,6 +766,7 @@ pdf
|
||||
perf
|
||||
perftools
|
||||
pgo
|
||||
phelter
|
||||
picoChip
|
||||
pinIndex
|
||||
pinout
|
||||
@@ -776,6 +784,7 @@ pragma
|
||||
pragmas
|
||||
pre
|
||||
precisions
|
||||
precompiled
|
||||
predefines
|
||||
prepareClone
|
||||
prepend
|
||||
@@ -805,6 +814,7 @@ radix
|
||||
randc
|
||||
randcase
|
||||
randstate
|
||||
raphmaster
|
||||
rarr
|
||||
rdtsc
|
||||
reStructuredText
|
||||
@@ -814,6 +824,7 @@ readmemb
|
||||
readmemh
|
||||
realpath
|
||||
realtime
|
||||
realtobits
|
||||
recoding
|
||||
recrem
|
||||
redeclaring
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "Vtop.h"
|
||||
|
||||
using namespace sc_core;
|
||||
using namespace sc_dt;
|
||||
|
||||
int sc_main(int argc, char* argv[]) {
|
||||
// This is a more complicated example, please also see the simpler examples/make_hello_c.
|
||||
@@ -52,7 +53,7 @@ int sc_main(int argc, char* argv[]) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// General logfile
|
||||
ios::sync_with_stdio();
|
||||
std::ios::sync_with_stdio();
|
||||
|
||||
// Define clocks
|
||||
sc_clock clk{"clk", 10, SC_NS, 0.5, 3, SC_NS, true};
|
||||
|
||||
@@ -60,8 +60,8 @@ class VlFileCopy:
|
||||
print("\t%s " % command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status != 0:
|
||||
raise Exception("Command failed running Verilator with '" +
|
||||
command + "', stopped")
|
||||
raise RuntimeError("Command failed running Verilator with '" +
|
||||
command + "', stopped")
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
@@ -83,8 +83,8 @@ class VlHierGraph:
|
||||
print("\t%s " % command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status != 0:
|
||||
raise Exception("Command failed running Verilator with '" +
|
||||
command + "', stopped")
|
||||
raise RuntimeError("Command failed running Verilator with '" +
|
||||
command + "', stopped")
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
@@ -2094,7 +2094,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
|
||||
|
||||
if (VL_UNLIKELY(m_end != ~0ULL && m_addr <= m_end && !m_anyAddr)) {
|
||||
VL_WARN_MT(m_filename.c_str(), m_linenum, "",
|
||||
"$readmem file ended before specified final address (IEEE 2017 21.4)");
|
||||
"$readmem file ended before specified final address (IEEE 1800-2017 21.4)");
|
||||
}
|
||||
|
||||
return false; // EOF
|
||||
@@ -3024,6 +3024,7 @@ void Verilated::endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
// It should be ok to call into endOfEvalGuts, it returns immediately
|
||||
// if there are no transactions.
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("End-of-eval cleanup\n"););
|
||||
VerilatedThreadMsgQueue::flush(evalMsgQp);
|
||||
evalMsgQp->process();
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -133,7 +133,8 @@ enum VerilatedVarType : uint8_t {
|
||||
VLVT_UINT32, // AKA IData
|
||||
VLVT_UINT64, // AKA QData
|
||||
VLVT_WDATA, // AKA WData
|
||||
VLVT_STRING // C++ string
|
||||
VLVT_STRING, // C++ string
|
||||
VLVT_REAL // AKA double
|
||||
};
|
||||
|
||||
enum VerilatedVarFlags {
|
||||
@@ -164,7 +165,9 @@ inline constexpr size_t roundUpToMultipleOf(size_t value) {
|
||||
// Return current thread ID (or 0), not super fast, cache if needed
|
||||
extern uint32_t VL_THREAD_ID() VL_MT_SAFE;
|
||||
|
||||
#ifndef VL_LOCK_SPINS
|
||||
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding
|
||||
#endif
|
||||
|
||||
/// Mutex, wrapped to allow -fthread_safety checks
|
||||
class VL_CAPABILITY("mutex") VerilatedMutex final {
|
||||
@@ -919,6 +922,7 @@ public:
|
||||
|
||||
// Internal: Called at end of each thread mtask, before finishing eval
|
||||
static void endOfThreadMTask(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
mtaskId(0);
|
||||
if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) endOfThreadMTaskGuts(evalMsgQp);
|
||||
}
|
||||
// Internal: Called at end of eval loop
|
||||
|
||||
+52
-14
@@ -9,6 +9,9 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
######################################################################
|
||||
|
||||
# Tool names.
|
||||
# These are computed at configuration time, and most are not ?=
|
||||
# to avoid picking up potentilly incorrect Make implicit variables
|
||||
AR = @AR@
|
||||
CXX = @CXX@
|
||||
LINK = @CXX@
|
||||
@@ -16,6 +19,7 @@ OBJCACHE ?= @OBJCACHE@
|
||||
PERL = @PERL@
|
||||
PYTHON3 = @PYTHON3@
|
||||
|
||||
# Configuration time options
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
|
||||
@@ -31,6 +35,12 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
|
||||
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
|
||||
# Compiler flags that enable coroutine support
|
||||
CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@
|
||||
# Compiler flags when creating a precompiled header
|
||||
CFG_CXXFLAGS_PCH = -x c++-header
|
||||
# Compiler option to put in front of filename to read precompiled header
|
||||
CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@
|
||||
# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC
|
||||
CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@
|
||||
# Linker flags
|
||||
CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@
|
||||
# Linker libraries for multithreading
|
||||
@@ -43,6 +53,12 @@ VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage
|
||||
VERILATOR_INCLUDER = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_includer
|
||||
VERILATOR_CCACHE_REPORT = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_ccache_report
|
||||
|
||||
######################################################################
|
||||
# CCACHE flags (via environment as no command line option available)
|
||||
|
||||
CCACHE_SLOPPINESS ?= pch_defines,time_macros
|
||||
export CCACHE_SLOPPINESS
|
||||
|
||||
######################################################################
|
||||
# Make checks
|
||||
|
||||
@@ -162,11 +178,17 @@ endif
|
||||
VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST)
|
||||
VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
|
||||
|
||||
# Precompiled header filename
|
||||
VK_PCH_H = $(VM_PREFIX)__pch.h
|
||||
# Compiler read-a-precompiled-header option for precompiled header filename
|
||||
VK_PCH_I_FAST = $(CFG_CXXFLAGS_PCH_I) $(VM_PREFIX)__pch.h.fast$(CFG_GCH_IF_CLANG)
|
||||
VK_PCH_I_SLOW = $(CFG_CXXFLAGS_PCH_I) $(VM_PREFIX)__pch.h.slow$(CFG_GCH_IF_CLANG)
|
||||
|
||||
#######################################################################
|
||||
### Overall Objects Linking
|
||||
|
||||
VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
|
||||
VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
|
||||
VK_OBJS_FAST = $(addsuffix .o, $(VM_FAST))
|
||||
VK_OBJS_SLOW = $(addsuffix .o, $(VM_SLOW))
|
||||
|
||||
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
|
||||
|
||||
@@ -193,7 +215,7 @@ else
|
||||
# Parallel build: Each .cpp file by itself. This can be somewhat slower for
|
||||
# very small designs and examples, but is a lot faster for large designs.
|
||||
|
||||
VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
|
||||
VK_OBJS += $(VK_OBJS_FAST) $(VK_OBJS_SLOW)
|
||||
endif
|
||||
|
||||
# When archiving just objects (.o), use single $(AR) run
|
||||
@@ -237,18 +259,32 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
|
||||
### Compile rules
|
||||
|
||||
ifneq ($(VM_DEFAULT_RULES),0)
|
||||
# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
|
||||
# and user files passed on the Verilator command line use this rule.
|
||||
# We put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
|
||||
# Compilation rule for anything not in $(VK_OBJS_FAST), $(VK_OBJS_SLOW), or
|
||||
# $(VK_GLOBAL_OBJS) including verilated.o. This typically means user files
|
||||
# passed on the Verilator command line.
|
||||
#
|
||||
# These rules put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to
|
||||
# allow USER_CPPFLAGS to override them
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
$(VK_SLOW_OBJS): %.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
$(VK_OBJS_FAST): %.o: %.cpp $(VK_PCH_H).fast.gch
|
||||
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(VK_PCH_I_FAST) -c -o $@ $<
|
||||
|
||||
$(VK_OBJS_SLOW): %.o: %.cpp $(VK_PCH_H).slow.gch
|
||||
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) $(VK_PCH_I_SLOW) -c -o $@ $<
|
||||
|
||||
$(VK_GLOBAL_OBJS): %.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
# Precompile a header file
|
||||
# PCH's compiler flags must match exactly the rules' above FAST/SLOW
|
||||
# arguments used for the .cpp files, or the PCH file won't be used.
|
||||
%.fast.gch: %
|
||||
$(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@
|
||||
%.slow.gch: %
|
||||
$(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) $(CFG_CXXFLAGS_PCH) $< -o $@
|
||||
|
||||
endif
|
||||
|
||||
#Default rule embedded in make:
|
||||
@@ -296,19 +332,21 @@ endif
|
||||
|
||||
debug-make::
|
||||
@echo
|
||||
@echo CXXFLAGS: $(CXXFLAGS)
|
||||
@echo CPPFLAGS: $(CPPFLAGS)
|
||||
@echo CXXFLAGS: $(CXXFLAGS)
|
||||
@echo OPT_FAST: $(OPT_FAST)
|
||||
@echo OPT_SLOW: $(OPT_SLOW)
|
||||
@echo VM_PREFIX: $(VM_PREFIX)
|
||||
@echo VM_PARALLEL_BUILDS: $(VM_PARALLEL_BUILDS)
|
||||
@echo VK_OBJS: $(VK_OBJS)
|
||||
@echo VK_OBJS_FAST: $(VK_OBJS_FAST)
|
||||
@echo VK_OBJS_SLOW: $(VK_OBJS_SLOW)
|
||||
@echo VM_CLASSES_FAST: $(VM_CLASSES_FAST)
|
||||
@echo VM_CLASSES_SLOW: $(VM_CLASSES_SLOW)
|
||||
@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
|
||||
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
|
||||
@echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST)
|
||||
@echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW)
|
||||
@echo VK_OBJS: $(VK_OBJS)
|
||||
@echo VM_PARALLEL_BUILDS: $(VM_PARALLEL_BUILDS)
|
||||
@echo VM_PREFIX: $(VM_PREFIX)
|
||||
@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
|
||||
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
|
||||
@echo
|
||||
|
||||
######################################################################
|
||||
|
||||
+115
-106
@@ -23,7 +23,6 @@
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define __STDC_LIMIT_MACROS // UINT64_MAX
|
||||
#include "verilated.h"
|
||||
#include "verilated_fst_c.h"
|
||||
|
||||
@@ -40,6 +39,7 @@
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
# include <io.h>
|
||||
@@ -50,33 +50,10 @@
|
||||
// clang-format on
|
||||
|
||||
//=============================================================================
|
||||
// Check that vltscope_t matches fstScopeType
|
||||
// Check that forward declared types matches the FST API types
|
||||
|
||||
static_assert(static_cast<int>(FST_ST_VCD_MODULE) == static_cast<int>(VLT_TRACE_SCOPE_MODULE),
|
||||
"VLT_TRACE_SCOPE_MODULE mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_TASK) == static_cast<int>(VLT_TRACE_SCOPE_TASK),
|
||||
"VLT_TRACE_SCOPE_TASK mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_FUNCTION) == static_cast<int>(VLT_TRACE_SCOPE_FUNCTION),
|
||||
"VLT_TRACE_SCOPE_FUNCTION mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_BEGIN) == static_cast<int>(VLT_TRACE_SCOPE_BEGIN),
|
||||
"VLT_TRACE_SCOPE_BEGIN mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_FORK) == static_cast<int>(VLT_TRACE_SCOPE_FORK),
|
||||
"VLT_TRACE_SCOPE_FORK mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_GENERATE) == static_cast<int>(VLT_TRACE_SCOPE_GENERATE),
|
||||
"VLT_TRACE_SCOPE_GENERATE mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_STRUCT) == static_cast<int>(VLT_TRACE_SCOPE_STRUCT),
|
||||
"VLT_TRACE_SCOPE_STRUCT mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_UNION) == static_cast<int>(VLT_TRACE_SCOPE_UNION),
|
||||
"VLT_TRACE_SCOPE_UNION mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_CLASS) == static_cast<int>(VLT_TRACE_SCOPE_CLASS),
|
||||
"VLT_TRACE_SCOPE_CLASS mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_INTERFACE)
|
||||
== static_cast<int>(VLT_TRACE_SCOPE_INTERFACE),
|
||||
"VLT_TRACE_SCOPE_INTERFACE mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_PACKAGE) == static_cast<int>(VLT_TRACE_SCOPE_PACKAGE),
|
||||
"VLT_TRACE_SCOPE_PACKAGE mismatches");
|
||||
static_assert(static_cast<int>(FST_ST_VCD_PROGRAM) == static_cast<int>(VLT_TRACE_SCOPE_PROGRAM),
|
||||
"VLT_TRACE_SCOPE_PROGRAM mismatches");
|
||||
static_assert(std::is_same<vlFstHandle, fstHandle>::value, "vlFstHandle mismatch");
|
||||
static_assert(std::is_same<vlFstEnumHandle, fstEnumHandle>::value, "vlFstHandle mismatch");
|
||||
|
||||
//=============================================================================
|
||||
// Specialization of the generics for this trace format
|
||||
@@ -104,19 +81,11 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
|
||||
fstWriterSetTimescaleFromString(m_fst, timeResStr().c_str()); // lintok-begin-on-ref
|
||||
if (m_useFstWriterThread) fstWriterSetParallelMode(m_fst, 1);
|
||||
constDump(true); // First dump must contain the const signals
|
||||
fullDump(true); // First dump must be full for fst
|
||||
|
||||
m_curScope.clear();
|
||||
|
||||
Super::traceInit();
|
||||
|
||||
// Clear the scope stack
|
||||
auto it = m_curScope.begin();
|
||||
while (it != m_curScope.end()) {
|
||||
fstWriterSetUpscope(m_fst);
|
||||
it = m_curScope.erase(it);
|
||||
}
|
||||
|
||||
// convert m_code2symbol into an array for fast lookup
|
||||
if (!m_symbolp) {
|
||||
m_symbolp = new fstHandle[nextCode()]{0};
|
||||
@@ -154,102 +123,142 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, uint32_t elemen
|
||||
m_local2fstdtype[dtypenum] = enumNum;
|
||||
}
|
||||
|
||||
void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, bool bussed, int msb,
|
||||
int lsb) {
|
||||
// TODO: should return std::optional<fstScopeType>, but I can't have C++17
|
||||
static std::pair<bool, fstScopeType> toFstScopeType(VerilatedTracePrefixType type) {
|
||||
switch (type) {
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE: return {true, FST_ST_VCD_MODULE};
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE: return {true, FST_ST_VCD_INTERFACE};
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
case VerilatedTracePrefixType::STRUCT_UNPACKED: return {true, FST_ST_VCD_STRUCT};
|
||||
case VerilatedTracePrefixType::UNION_PACKED: return {true, FST_ST_VCD_UNION};
|
||||
default: return {false, /* unused so whatever, just need a value */ FST_ST_VCD_SCOPE};
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedFst::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
|
||||
const std::string newPrefix = m_prefixStack.back().first + name;
|
||||
const auto pair = toFstScopeType(type);
|
||||
const bool properScope = pair.first;
|
||||
const fstScopeType scopeType = pair.second;
|
||||
m_prefixStack.emplace_back(newPrefix + (properScope ? " " : ""), type);
|
||||
if (properScope) {
|
||||
const std::string scopeName = lastWord(newPrefix);
|
||||
fstWriterSetScope(m_fst, scopeType, scopeName.c_str(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedFst::popPrefix() {
|
||||
const bool properScope = toFstScopeType(m_prefixStack.back().second).first;
|
||||
if (properScope) fstWriterSetUpscope(m_fst);
|
||||
m_prefixStack.pop_back();
|
||||
assert(!m_prefixStack.empty());
|
||||
}
|
||||
|
||||
void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
||||
VerilatedTraceSigType type, bool array, int arraynum, bool bussed,
|
||||
int msb, int lsb) {
|
||||
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||
|
||||
const bool enabled = Super::declCode(code, name, bits, false);
|
||||
const std::string hierarchicalName = m_prefixStack.back().first + name;
|
||||
|
||||
const bool enabled = Super::declCode(code, hierarchicalName, bits);
|
||||
if (!enabled) return;
|
||||
|
||||
std::string nameasstr = namePrefix() + name;
|
||||
std::istringstream nameiss{nameasstr};
|
||||
std::istream_iterator<std::string> beg(nameiss);
|
||||
std::istream_iterator<std::string> end;
|
||||
std::list<std::string> tokens(beg, end); // Split name
|
||||
std::string symbol_name{tokens.back()};
|
||||
tokens.pop_back(); // Remove symbol name from hierarchy
|
||||
std::string tmpModName;
|
||||
|
||||
// Find point where current and new scope diverge
|
||||
auto cur_it = m_curScope.begin();
|
||||
auto new_it = tokens.begin();
|
||||
while (cur_it != m_curScope.end() && new_it != tokens.end()) {
|
||||
if (*cur_it != *new_it) break;
|
||||
++cur_it;
|
||||
++new_it;
|
||||
}
|
||||
|
||||
// Go back to the common point
|
||||
while (cur_it != m_curScope.end()) {
|
||||
fstWriterSetUpscope(m_fst);
|
||||
cur_it = m_curScope.erase(cur_it);
|
||||
}
|
||||
|
||||
// Follow the hierarchy of the new variable from the common scope point
|
||||
while (new_it != tokens.end()) {
|
||||
if ((new_it->back() & 0x80)) {
|
||||
tmpModName = *new_it;
|
||||
tmpModName.pop_back();
|
||||
// If the scope ends with a non-ASCII character, it will be 0x80 + fstScopeType
|
||||
fstWriterSetScope(m_fst, static_cast<fstScopeType>(new_it->back() & 0x7f),
|
||||
tmpModName.c_str(), nullptr);
|
||||
} else {
|
||||
fstWriterSetScope(m_fst, FST_ST_VCD_SCOPE, new_it->c_str(), nullptr);
|
||||
}
|
||||
m_curScope.push_back(*new_it);
|
||||
new_it = tokens.erase(new_it);
|
||||
}
|
||||
|
||||
assert(hierarchicalName.rfind(' ') != std::string::npos);
|
||||
std::stringstream name_ss;
|
||||
name_ss << symbol_name;
|
||||
name_ss << lastWord(hierarchicalName);
|
||||
if (array) name_ss << "[" << arraynum << "]";
|
||||
if (bussed) name_ss << " [" << msb << ":" << lsb << "]";
|
||||
std::string name_str = name_ss.str();
|
||||
const std::string name_str = name_ss.str();
|
||||
|
||||
if (dtypenum > 0) {
|
||||
const fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
|
||||
fstWriterEmitEnumTableRef(m_fst, enumNum);
|
||||
if (dtypenum > 0) fstWriterEmitEnumTableRef(m_fst, m_local2fstdtype[dtypenum]);
|
||||
|
||||
fstVarDir varDir;
|
||||
switch (direction) {
|
||||
case VerilatedTraceSigDirection::INOUT: varDir = FST_VD_INOUT; break;
|
||||
case VerilatedTraceSigDirection::OUTPUT: varDir = FST_VD_OUTPUT; break;
|
||||
case VerilatedTraceSigDirection::INPUT: varDir = FST_VD_INPUT; break;
|
||||
case VerilatedTraceSigDirection::NONE: varDir = FST_VD_IMPLICIT; break;
|
||||
}
|
||||
|
||||
fstVarType varType;
|
||||
// Doubles have special decoding properties, so must indicate if a double
|
||||
if (type == VerilatedTraceSigType::DOUBLE) {
|
||||
if (kind == VerilatedTraceSigKind::PARAMETER) {
|
||||
varType = FST_VT_VCD_REAL_PARAMETER;
|
||||
} else {
|
||||
varType = FST_VT_VCD_REAL;
|
||||
}
|
||||
}
|
||||
// clang-format off
|
||||
else if (kind == VerilatedTraceSigKind::PARAMETER) varType = FST_VT_VCD_PARAMETER;
|
||||
else if (kind == VerilatedTraceSigKind::SUPPLY0) varType = FST_VT_VCD_SUPPLY0;
|
||||
else if (kind == VerilatedTraceSigKind::SUPPLY1) varType = FST_VT_VCD_SUPPLY1;
|
||||
else if (kind == VerilatedTraceSigKind::TRI) varType = FST_VT_VCD_TRI;
|
||||
else if (kind == VerilatedTraceSigKind::TRI0) varType = FST_VT_VCD_TRI0;
|
||||
else if (kind == VerilatedTraceSigKind::TRI1) varType = FST_VT_VCD_TRI1;
|
||||
else if (kind == VerilatedTraceSigKind::WIRE) varType = FST_VT_VCD_WIRE;
|
||||
//
|
||||
else if (type == VerilatedTraceSigType::INTEGER) varType = FST_VT_VCD_INTEGER;
|
||||
else if (type == VerilatedTraceSigType::BIT) varType = FST_VT_SV_BIT;
|
||||
else if (type == VerilatedTraceSigType::LOGIC) varType = FST_VT_SV_LOGIC;
|
||||
else if (type == VerilatedTraceSigType::INT) varType = FST_VT_SV_INT;
|
||||
else if (type == VerilatedTraceSigType::SHORTINT) varType = FST_VT_SV_SHORTINT;
|
||||
else if (type == VerilatedTraceSigType::LONGINT) varType = FST_VT_SV_LONGINT;
|
||||
else if (type == VerilatedTraceSigType::BYTE) varType = FST_VT_SV_BYTE;
|
||||
else if (type == VerilatedTraceSigType::EVENT) varType = FST_VT_VCD_EVENT;
|
||||
else if (type == VerilatedTraceSigType::TIME) varType = FST_VT_VCD_TIME;
|
||||
else { assert(0); /* Unreachable */ }
|
||||
// clang-format on
|
||||
|
||||
const auto it = vlstd::as_const(m_code2symbol).find(code);
|
||||
if (it == m_code2symbol.end()) { // New
|
||||
m_code2symbol[code]
|
||||
= fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
|
||||
= fstWriterCreateVar(m_fst, varType, varDir, bits, name_str.c_str(), 0);
|
||||
} else { // Alias
|
||||
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), it->second);
|
||||
fstWriterCreateVar(m_fst, varType, varDir, bits, name_str.c_str(), it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedFst::declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
|
||||
void VerilatedFst::declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
||||
VerilatedTraceSigType type, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, direction, kind, type, array, arraynum, false, 0, 0);
|
||||
}
|
||||
void VerilatedFst::declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
|
||||
void VerilatedFst::declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
||||
VerilatedTraceSigType type, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, direction, kind, type, array, arraynum, false, 0, 0);
|
||||
}
|
||||
void VerilatedFst::declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
|
||||
void VerilatedFst::declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
||||
VerilatedTraceSigType type, bool array, int arraynum, int msb,
|
||||
int lsb) {
|
||||
declare(code, name, dtypenum, direction, kind, type, array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedFst::declQuad(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
|
||||
void VerilatedFst::declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
||||
VerilatedTraceSigType type, bool array, int arraynum, int msb,
|
||||
int lsb) {
|
||||
declare(code, name, dtypenum, direction, kind, type, array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedFst::declArray(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, true, msb, lsb);
|
||||
void VerilatedFst::declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
||||
VerilatedTraceSigType type, bool array, int arraynum, int msb,
|
||||
int lsb) {
|
||||
declare(code, name, dtypenum, direction, kind, type, array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 63, 0);
|
||||
void VerilatedFst::declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection direction, VerilatedTraceSigKind kind,
|
||||
VerilatedTraceSigType type, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, direction, kind, type, array, arraynum, false, 63, 0);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Get/commit trace buffer
|
||||
|
||||
VerilatedFst::Buffer* VerilatedFst::getTraceBuffer() {
|
||||
VerilatedFst::Buffer* VerilatedFst::getTraceBuffer(uint32_t fidx) {
|
||||
if (offload()) return new OffloadBuffer{*this};
|
||||
return new Buffer{*this};
|
||||
}
|
||||
@@ -284,7 +293,7 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
|
||||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitEvent(uint32_t code, VlEvent newval) {
|
||||
void VerilatedFstBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
|
||||
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
|
||||
}
|
||||
|
||||
+37
-23
@@ -24,13 +24,14 @@
|
||||
#include "verilated.h"
|
||||
#include "verilated_trace.h"
|
||||
|
||||
#include "gtkwave/fstapi.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef uint32_t vlFstHandle;
|
||||
typedef uint32_t vlFstEnumHandle;
|
||||
|
||||
class VerilatedFstBuffer;
|
||||
|
||||
//=============================================================================
|
||||
@@ -49,18 +50,22 @@ private:
|
||||
// FST specific internals
|
||||
|
||||
void* m_fst = nullptr;
|
||||
std::map<uint32_t, fstHandle> m_code2symbol;
|
||||
std::map<int, fstEnumHandle> m_local2fstdtype;
|
||||
std::list<std::string> m_curScope;
|
||||
fstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array
|
||||
std::map<uint32_t, vlFstHandle> m_code2symbol;
|
||||
std::map<int, vlFstEnumHandle> m_local2fstdtype;
|
||||
vlFstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array
|
||||
char* m_strbufp = nullptr; // String buffer long enough to hold maxBits() chars
|
||||
|
||||
bool m_useFstWriterThread = false; // Whether to use the separate FST writer thread
|
||||
|
||||
// Prefixes to add to signal names/scope types
|
||||
std::vector<std::pair<std::string, VerilatedTracePrefixType>> m_prefixStack{
|
||||
{"", VerilatedTracePrefixType::SCOPE_MODULE}};
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFst);
|
||||
void declare(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, bool bussed, int msb, int lsb);
|
||||
void declare(uint32_t code, const char* name, int dtypenum, VerilatedTraceSigDirection,
|
||||
VerilatedTraceSigKind, VerilatedTraceSigType, bool array, int arraynum,
|
||||
bool bussed, int msb, int lsb);
|
||||
|
||||
protected:
|
||||
//=========================================================================
|
||||
@@ -74,7 +79,7 @@ protected:
|
||||
bool preChangeDump() override { return isOpen(); }
|
||||
|
||||
// Trace buffer management
|
||||
Buffer* getTraceBuffer() override;
|
||||
Buffer* getTraceBuffer(uint32_t fidx) override;
|
||||
void commitTraceBuffer(Buffer*) override;
|
||||
|
||||
// Configure sub-class
|
||||
@@ -101,18 +106,27 @@ public:
|
||||
//=========================================================================
|
||||
// Internal interface to Verilator generated code
|
||||
|
||||
void declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
void declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
void declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||
void declArray(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||
void declDouble(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
void pushPrefix(const std::string&, VerilatedTracePrefixType);
|
||||
void popPrefix();
|
||||
|
||||
void declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum);
|
||||
void declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum);
|
||||
void declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum, int msb, int lsb);
|
||||
void declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum, int msb, int lsb);
|
||||
void declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum);
|
||||
|
||||
void declDTypeEnum(int dtypenum, const char* name, uint32_t elements, unsigned int minValbits,
|
||||
const char** itemNamesp, const char** itemValuesp);
|
||||
@@ -149,7 +163,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
|
||||
// The FST file handle
|
||||
void* const m_fst = m_owner.m_fst;
|
||||
// code to fstHande map, as an array
|
||||
const fstHandle* const m_symbolp = m_owner.m_symbolp;
|
||||
const vlFstHandle* const m_symbolp = m_owner.m_symbolp;
|
||||
// String buffer long enough to hold maxBits() chars
|
||||
char* const m_strbufp = m_owner.m_strbufp;
|
||||
|
||||
@@ -163,7 +177,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
|
||||
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
|
||||
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||
|
||||
+78
-63
@@ -344,8 +344,8 @@ uint64_t vl_time_pow10(int n) VL_PURE;
|
||||
|
||||
// Output clean
|
||||
// EMIT_RULE: VL_CLEAN: oclean=clean; obits=lbits;
|
||||
#define VL_CLEAN_II(obits, lbits, lhs) ((lhs)&VL_MASK_I(obits))
|
||||
#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs)&VL_MASK_Q(obits))
|
||||
#define VL_CLEAN_II(obits, lbits, lhs) ((lhs) & (VL_MASK_I(obits)))
|
||||
#define VL_CLEAN_QQ(obits, lbits, lhs) ((lhs) & (VL_MASK_Q(obits)))
|
||||
|
||||
// EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits;
|
||||
#define VL_ASSIGNCLEAN_W(obits, owp, lwp) VL_CLEAN_WW((obits), (owp), (lwp))
|
||||
@@ -449,7 +449,7 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
|
||||
#define VL_ASSIGN_WSB(obits, owp, svar) \
|
||||
{ \
|
||||
const int words = VL_WORDS_I(obits); \
|
||||
sc_biguint<(obits)> _butemp = (svar).read(); \
|
||||
sc_dt::sc_biguint<(obits)> _butemp = (svar).read(); \
|
||||
uint32_t* chunkp = _butemp.get_raw(); \
|
||||
int32_t lsb = 0; \
|
||||
while (lsb < obits - BITS_PER_DIGIT) { \
|
||||
@@ -475,20 +475,20 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
|
||||
|
||||
#define VL_ASSIGN_SWI(obits, svar, rd) \
|
||||
{ \
|
||||
sc_bv<(obits)> _bvtemp; \
|
||||
sc_dt::sc_bv<(obits)> _bvtemp; \
|
||||
_bvtemp.set_word(0, (rd)); \
|
||||
(svar).write(_bvtemp); \
|
||||
}
|
||||
#define VL_ASSIGN_SWQ(obits, svar, rd) \
|
||||
{ \
|
||||
sc_bv<(obits)> _bvtemp; \
|
||||
sc_dt::sc_bv<(obits)> _bvtemp; \
|
||||
_bvtemp.set_word(0, static_cast<IData>(rd)); \
|
||||
_bvtemp.set_word(1, static_cast<IData>((rd) >> VL_IDATASIZE)); \
|
||||
(svar).write(_bvtemp); \
|
||||
}
|
||||
#define VL_ASSIGN_SWW(obits, svar, rwp) \
|
||||
{ \
|
||||
sc_bv<(obits)> _bvtemp; \
|
||||
sc_dt::sc_bv<(obits)> _bvtemp; \
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) _bvtemp.set_word(i, (rwp)[i]); \
|
||||
(svar).write(_bvtemp); \
|
||||
}
|
||||
@@ -504,7 +504,7 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
|
||||
#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT
|
||||
#define VL_ASSIGN_SBW(obits, svar, rwp) \
|
||||
{ \
|
||||
sc_biguint<(obits)> _butemp; \
|
||||
sc_dt::sc_biguint<(obits)> _butemp; \
|
||||
int32_t lsb = 0; \
|
||||
uint32_t* chunkp = _butemp.get_raw(); \
|
||||
while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \
|
||||
@@ -1437,7 +1437,7 @@ static inline IData VL_STREAML_FAST_III(int lbits, IData ld, IData rd_log2) VL_P
|
||||
if (rd_log2) {
|
||||
const uint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2); // max multiple of rd <= lbits
|
||||
const uint32_t lbitsRem = lbits - lbitsFloor; // number of bits in most-sig slice (MSS)
|
||||
const IData msbMask = VL_MASK_I(lbitsRem) << lbitsFloor; // mask to sel only bits in MSS
|
||||
const IData msbMask = lbitsFloor == 32 ? 0UL : VL_MASK_I(lbitsRem) << lbitsFloor;
|
||||
ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_UL(1) << rd_log2) - lbitsRem));
|
||||
}
|
||||
switch (rd_log2) {
|
||||
@@ -1647,6 +1647,24 @@ static inline void _vl_shiftl_inplace_w(int obits, WDataOutP iowp,
|
||||
// EMIT_RULE: VL_SHIFTL: oclean=lclean; rclean==clean;
|
||||
// Important: Unlike most other funcs, the shift might well be a computed
|
||||
// expression. Thus consider this when optimizing. (And perhaps have 2 funcs?)
|
||||
// If RHS (rd/rwp) is larger than the output, zeros (or all ones for >>>) must be returned
|
||||
// (This corresponds to AstShift*Ovr Ast nodes)
|
||||
static inline IData VL_SHIFTL_III(int obits, int, int, IData lhs, IData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
|
||||
return lhs << rhs; // Small is common so not clean return
|
||||
}
|
||||
static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
|
||||
return VL_CLEAN_II(obits, obits, lhs << rhs);
|
||||
}
|
||||
static inline QData VL_SHIFTL_QQI(int obits, int, int, QData lhs, IData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
|
||||
return lhs << rhs; // Small is common so not clean return
|
||||
}
|
||||
static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs << rhs);
|
||||
}
|
||||
static inline WDataOutP VL_SHIFTL_WWI(int obits, int, int, WDataOutP owp, WDataInP const lwp,
|
||||
IData rd) VL_MT_SAFE {
|
||||
const int word_shift = VL_BITWORD_E(rd);
|
||||
@@ -1684,11 +1702,7 @@ static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs,
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return VL_CLEAN_II(obits, obits, lhs << rwp[0]);
|
||||
}
|
||||
static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
|
||||
return VL_CLEAN_II(obits, obits, lhs << rhs);
|
||||
return VL_SHIFTL_III(obits, obits, 32, lhs, rwp[0]);
|
||||
}
|
||||
static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs,
|
||||
WDataInP const rwp) VL_MT_SAFE {
|
||||
@@ -1698,16 +1712,28 @@ static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs,
|
||||
}
|
||||
}
|
||||
// Above checks rwp[1]==0 so not needed in below shift
|
||||
return VL_CLEAN_QQ(obits, obits, lhs << (static_cast<QData>(rwp[0])));
|
||||
}
|
||||
static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs << rhs);
|
||||
return VL_SHIFTL_QQI(obits, obits, 32, lhs, rwp[0]);
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean;
|
||||
// Important: Unlike most other funcs, the shift might well be a computed
|
||||
// expression. Thus consider this when optimizing. (And perhaps have 2 funcs?)
|
||||
static inline IData VL_SHIFTR_III(int obits, int, int, IData lhs, IData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
|
||||
return lhs >> rhs; // Small is common so assumed not clean
|
||||
}
|
||||
static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
|
||||
}
|
||||
static inline QData VL_SHIFTR_QQI(int obits, int, int, QData lhs, IData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
|
||||
return lhs >> rhs; // Small is common so assumed not clean
|
||||
}
|
||||
static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
|
||||
}
|
||||
static inline WDataOutP VL_SHIFTR_WWI(int obits, int, int, WDataOutP owp, WDataInP const lwp,
|
||||
IData rd) VL_MT_SAFE {
|
||||
const int word_shift = VL_BITWORD_E(rd); // Maybe 0
|
||||
@@ -1751,29 +1777,16 @@ static inline WDataOutP VL_SHIFTR_WWQ(int obits, int lbits, int rbits, WDataOutP
|
||||
static inline IData VL_SHIFTR_IIW(int obits, int, int rbits, IData lhs,
|
||||
WDataInP const rwp) VL_PURE {
|
||||
for (int i = 1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
return 0;
|
||||
}
|
||||
if (VL_UNLIKELY(rwp[i])) return 0; // Huge shift 1>>32 or more
|
||||
}
|
||||
return VL_CLEAN_II(obits, obits, lhs >> rwp[0]);
|
||||
return VL_SHIFTR_III(obits, obits, 32, lhs, rwp[0]);
|
||||
}
|
||||
static inline QData VL_SHIFTR_QQW(int obits, int, int rbits, QData lhs,
|
||||
WDataInP const rwp) VL_PURE {
|
||||
for (int i = 1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
return 0;
|
||||
}
|
||||
if (VL_UNLIKELY(rwp[i])) return 0; // Huge shift 1>>32 or more
|
||||
}
|
||||
// Above checks rwp[1]==0 so not needed in below shift
|
||||
return VL_CLEAN_QQ(obits, obits, lhs >> (static_cast<QData>(rwp[0])));
|
||||
}
|
||||
static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
|
||||
}
|
||||
static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_PURE {
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
|
||||
return VL_SHIFTR_QQI(obits, obits, 32, lhs, rwp[0]);
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean;
|
||||
@@ -1783,11 +1796,13 @@ static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData r
|
||||
// must use lbits for sign; lbits might != obits,
|
||||
// an EXTEND(SHIFTRS(...)) can became a SHIFTRS(...) within same 32/64 bit word length
|
||||
const IData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return sign & VL_MASK_I(obits);
|
||||
const IData signext = ~(VL_MASK_I(lbits) >> rhs); // One with bits where we've shifted "past"
|
||||
return (lhs >> rhs) | (sign & VL_CLEAN_II(obits, obits, signext));
|
||||
}
|
||||
static inline QData VL_SHIFTRS_QQI(int obits, int lbits, int, QData lhs, IData rhs) VL_PURE {
|
||||
const QData sign = -(lhs >> (lbits - 1));
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return sign & VL_MASK_Q(obits);
|
||||
const QData signext = ~(VL_MASK_Q(lbits) >> rhs);
|
||||
return (lhs >> rhs) | (sign & VL_CLEAN_QQ(obits, obits, signext));
|
||||
}
|
||||
@@ -2111,60 +2126,60 @@ static inline WDataOutP VL_CONST_W_8X(int obits, WDataOutP o,
|
||||
VL_C_END_(obits, 8);
|
||||
}
|
||||
//
|
||||
static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP obase,
|
||||
static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP o,
|
||||
EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0;
|
||||
WDataOutP ohi = o + VL_WORDS_I(lsb);
|
||||
ohi[0] = d0;
|
||||
VL_C_END_(obits, VL_WORDS_I(lsb) + 1);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP obase,
|
||||
static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP o,
|
||||
EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1;
|
||||
WDataOutP ohi = o + VL_WORDS_I(lsb);
|
||||
ohi[0] = d0; ohi[1] = d1;
|
||||
VL_C_END_(obits, VL_WORDS_I(lsb) + 2);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP obase,
|
||||
static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP o,
|
||||
EData d2, EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2;
|
||||
WDataOutP ohi = o + VL_WORDS_I(lsb);
|
||||
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2;
|
||||
VL_C_END_(obits, VL_WORDS_I(lsb) + 3);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP obase,
|
||||
static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP o,
|
||||
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
WDataOutP ohi = o + VL_WORDS_I(lsb);
|
||||
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
|
||||
VL_C_END_(obits, VL_WORDS_I(lsb) + 4);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase,
|
||||
static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP o,
|
||||
EData d4,
|
||||
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
o[4] = d4;
|
||||
WDataOutP ohi = o + VL_WORDS_I(lsb);
|
||||
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
|
||||
ohi[4] = d4;
|
||||
VL_C_END_(obits, VL_WORDS_I(lsb) + 5);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase,
|
||||
static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP o,
|
||||
EData d5, EData d4,
|
||||
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
o[4] = d4; o[5] = d5;
|
||||
WDataOutP ohi = o + VL_WORDS_I(lsb);
|
||||
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
|
||||
ohi[4] = d4; ohi[5] = d5;
|
||||
VL_C_END_(obits, VL_WORDS_I(lsb) + 6);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase,
|
||||
static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP o,
|
||||
EData d6, EData d5, EData d4,
|
||||
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
o[4] = d4; o[5] = d5; o[6] = d6;
|
||||
WDataOutP ohi = o + VL_WORDS_I(lsb);
|
||||
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
|
||||
ohi[4] = d4; ohi[5] = d5; ohi[6] = d6;
|
||||
VL_C_END_(obits, VL_WORDS_I(lsb) + 7);
|
||||
}
|
||||
static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase,
|
||||
static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP o,
|
||||
EData d7, EData d6, EData d5, EData d4,
|
||||
EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE {
|
||||
WDataOutP o = obase + VL_WORDS_I(lsb);
|
||||
o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3;
|
||||
o[4] = d4; o[5] = d5; o[6] = d6; o[7] = d7;
|
||||
WDataOutP ohi = o + VL_WORDS_I(lsb);
|
||||
ohi[0] = d0; ohi[1] = d1; ohi[2] = d2; ohi[3] = d3;
|
||||
ohi[4] = d4; ohi[5] = d5; ohi[6] = d6; ohi[7] = d7;
|
||||
VL_C_END_(obits, VL_WORDS_I(lsb) + 8);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,12 +161,18 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
|
||||
|
||||
// TODO Perhaps merge with verilated_coverage output format, so can
|
||||
// have a common merging and reporting tool, etc.
|
||||
fprintf(fp, "VLPROFVERSION 2.0 # Verilator execution profile version 2.0\n");
|
||||
fprintf(fp, "VLPROFVERSION 2.1 # Verilator execution profile version 2.1\n");
|
||||
fprintf(fp, "VLPROF arg +verilator+prof+exec+start+%" PRIu64 "\n",
|
||||
Verilated::threadContextp()->profExecStart());
|
||||
fprintf(fp, "VLPROF arg +verilator+prof+exec+window+%u\n",
|
||||
Verilated::threadContextp()->profExecWindow());
|
||||
const unsigned threads = static_cast<unsigned>(m_traceps.size());
|
||||
// Note that VerilatedContext will by default create as many threads as there are hardware
|
||||
// processors, but not all of them might be utilized. Report the actual number that has trace
|
||||
// entries to avoid over-counting.
|
||||
unsigned threads = 0;
|
||||
for (const auto& pair : m_traceps) {
|
||||
if (!pair.second->empty()) ++threads;
|
||||
}
|
||||
fprintf(fp, "VLPROF stat threads %u\n", threads);
|
||||
fprintf(fp, "VLPROF stat yields %" PRIu64 "\n", VlMTaskVertex::yields());
|
||||
|
||||
@@ -183,6 +189,7 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
|
||||
for (const auto& pair : m_traceps) {
|
||||
const uint32_t threadId = pair.first;
|
||||
ExecutionTrace* const tracep = pair.second;
|
||||
if (tracep->empty()) continue;
|
||||
fprintf(fp, "VLPROFTHREAD %" PRIu32 "\n", threadId);
|
||||
|
||||
for (const VlExecutionRecord& er : *tracep) {
|
||||
@@ -191,10 +198,9 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
|
||||
fprintf(fp, "VLPROFEXEC %s %" PRIu64, name, time);
|
||||
|
||||
switch (er.m_type) {
|
||||
case VlExecutionRecord::Type::EVAL_BEGIN:
|
||||
case VlExecutionRecord::Type::EVAL_END:
|
||||
case VlExecutionRecord::Type::EVAL_LOOP_BEGIN:
|
||||
case VlExecutionRecord::Type::EVAL_LOOP_END:
|
||||
case VlExecutionRecord::Type::SECTION_POP:
|
||||
case VlExecutionRecord::Type::EXEC_GRAPH_BEGIN:
|
||||
case VlExecutionRecord::Type::EXEC_GRAPH_END:
|
||||
// No payload
|
||||
fprintf(fp, "\n");
|
||||
break;
|
||||
@@ -209,6 +215,11 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
|
||||
fprintf(fp, " id %u predictCost %u\n", payload.m_id, payload.m_predictCost);
|
||||
break;
|
||||
}
|
||||
case VlExecutionRecord::Type::SECTION_PUSH: {
|
||||
const auto& payload = er.m_payload.sectionPush;
|
||||
fprintf(fp, " %s\n", payload.m_name);
|
||||
break;
|
||||
}
|
||||
default: abort(); // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ VL_ATTR_ALWINLINE QData VL_CPU_TICK() {
|
||||
|
||||
// clang-format off
|
||||
#define FOREACH_VlExecutionRecord_TYPE(macro) \
|
||||
_VL_FOREACH_APPLY(macro, EVAL_BEGIN) \
|
||||
_VL_FOREACH_APPLY(macro, EVAL_END) \
|
||||
_VL_FOREACH_APPLY(macro, EVAL_LOOP_BEGIN) \
|
||||
_VL_FOREACH_APPLY(macro, EVAL_LOOP_END) \
|
||||
_VL_FOREACH_APPLY(macro, SECTION_PUSH) \
|
||||
_VL_FOREACH_APPLY(macro, SECTION_POP) \
|
||||
_VL_FOREACH_APPLY(macro, MTASK_BEGIN) \
|
||||
_VL_FOREACH_APPLY(macro, MTASK_END)
|
||||
_VL_FOREACH_APPLY(macro, MTASK_END) \
|
||||
_VL_FOREACH_APPLY(macro, EXEC_GRAPH_BEGIN) \
|
||||
_VL_FOREACH_APPLY(macro, EXEC_GRAPH_END)
|
||||
// clang-format on
|
||||
|
||||
class VlExecutionRecord final {
|
||||
@@ -83,6 +83,9 @@ class VlExecutionRecord final {
|
||||
};
|
||||
|
||||
union Payload {
|
||||
struct {
|
||||
const char* m_name; // Name of section being entered
|
||||
} sectionPush;
|
||||
struct {
|
||||
uint32_t m_id; // MTask id
|
||||
uint32_t m_predictStart; // Time scheduler predicted would start
|
||||
@@ -109,10 +112,11 @@ public:
|
||||
VlExecutionRecord() = default;
|
||||
|
||||
// METHODS
|
||||
void evalBegin() { m_type = Type::EVAL_BEGIN; }
|
||||
void evalEnd() { m_type = Type::EVAL_END; }
|
||||
void evalLoopBegin() { m_type = Type::EVAL_LOOP_BEGIN; }
|
||||
void evalLoopEnd() { m_type = Type::EVAL_LOOP_END; }
|
||||
void sectionPush(const char* name) {
|
||||
m_payload.sectionPush.m_name = name;
|
||||
m_type = Type::SECTION_PUSH;
|
||||
}
|
||||
void sectionPop() { m_type = Type::SECTION_POP; }
|
||||
void mtaskBegin(uint32_t id, uint32_t predictStart) {
|
||||
m_payload.mtaskBegin.m_id = id;
|
||||
m_payload.mtaskBegin.m_predictStart = predictStart;
|
||||
@@ -124,6 +128,8 @@ public:
|
||||
m_payload.mtaskEnd.m_predictCost = predictCost;
|
||||
m_type = Type::MTASK_END;
|
||||
}
|
||||
void execGraphBegin() { m_type = Type::EXEC_GRAPH_BEGIN; }
|
||||
void execGraphEnd() { m_type = Type::EXEC_GRAPH_END; }
|
||||
};
|
||||
|
||||
static_assert(std::is_trivially_destructible<VlExecutionRecord>::value,
|
||||
|
||||
@@ -47,7 +47,7 @@ package std;
|
||||
endtask
|
||||
|
||||
function int try_put(T message);
|
||||
if (num() < m_bound) begin
|
||||
if (m_bound == 0 || num() < m_bound) begin
|
||||
m_queue.push_back(message);
|
||||
return 1;
|
||||
end
|
||||
|
||||
@@ -153,11 +153,12 @@ void VlTriggerScheduler::dump(const char* eventDescription) const {
|
||||
// VlDynamicTriggerScheduler:: Methods
|
||||
|
||||
bool VlDynamicTriggerScheduler::evaluate() {
|
||||
m_anyTriggered = false;
|
||||
VL_DEBUG_IF(dump(););
|
||||
std::swap(m_suspended, m_evaluated);
|
||||
for (auto& coro : m_evaluated) coro.resume();
|
||||
m_evaluated.clear();
|
||||
return !m_triggered.empty();
|
||||
return m_anyTriggered;
|
||||
}
|
||||
|
||||
void VlDynamicTriggerScheduler::doPostUpdates() {
|
||||
|
||||
@@ -275,6 +275,7 @@ public:
|
||||
// co_await __VdynSched.evaluation();
|
||||
// <pre updates>;
|
||||
// __Vtrigger = <trigger eval>;
|
||||
// __VdynShed.anyTriggered(__Vtrigger);
|
||||
// [optionally] co_await __VdynSched.postUpdate();
|
||||
// <post updates>;
|
||||
// }
|
||||
@@ -288,6 +289,7 @@ class VlDynamicTriggerScheduler final {
|
||||
using VlCoroutineVec = std::vector<VlCoroutineHandle>;
|
||||
|
||||
// MEMBERS
|
||||
bool m_anyTriggered = false; // If true, at least one trigger was set
|
||||
VlCoroutineVec m_suspended; // Suspended coroutines awaiting trigger evaluation
|
||||
VlCoroutineVec m_evaluated; // Coroutines currently being evaluated (for evaluate())
|
||||
VlCoroutineVec m_triggered; // Coroutines whose triggers were set, and are awaiting resumption
|
||||
@@ -313,6 +315,8 @@ class VlDynamicTriggerScheduler final {
|
||||
public:
|
||||
// Evaluates all dynamic triggers (resumed coroutines that co_await evaluation())
|
||||
bool evaluate();
|
||||
// Called by coroutines that evaluate triggers to notify the scheduler if any triggers were set
|
||||
void anyTriggered(bool triggered) { m_anyTriggered = m_anyTriggered || triggered; }
|
||||
// Runs post updates for all dynamic triggers (resumes coroutines that co_await postUpdate())
|
||||
void doPostUpdates();
|
||||
// Resumes all coroutines whose triggers are set (those that co_await resumption())
|
||||
|
||||
+82
-28
@@ -25,7 +25,6 @@
|
||||
// clang-format off
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_trace_defs.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <condition_variable>
|
||||
@@ -46,6 +45,54 @@ class VerilatedTraceBuffer;
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceOffloadBuffer;
|
||||
|
||||
//=============================================================================
|
||||
// Common enumerations
|
||||
|
||||
enum class VerilatedTracePrefixType : uint32_t {
|
||||
// Note: Entries must match VTracePrefixType (by name, not necessarily by value)
|
||||
ARRAY_PACKED,
|
||||
ARRAY_UNPACKED,
|
||||
SCOPE_MODULE,
|
||||
SCOPE_INTERFACE,
|
||||
STRUCT_PACKED,
|
||||
STRUCT_UNPACKED,
|
||||
UNION_PACKED
|
||||
};
|
||||
|
||||
// Direction attribute for ports
|
||||
enum class VerilatedTraceSigDirection : uint32_t {
|
||||
NONE,
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
INOUT,
|
||||
};
|
||||
|
||||
// Kind of signal. Similar to nettype but with a few more alternatives
|
||||
enum class VerilatedTraceSigKind : uint32_t {
|
||||
PARAMETER,
|
||||
SUPPLY0,
|
||||
SUPPLY1,
|
||||
TRI,
|
||||
TRI0,
|
||||
TRI1,
|
||||
WIRE,
|
||||
VAR,
|
||||
};
|
||||
|
||||
// Base data type of signal
|
||||
enum class VerilatedTraceSigType : uint32_t {
|
||||
DOUBLE,
|
||||
INTEGER,
|
||||
BIT,
|
||||
LOGIC,
|
||||
INT,
|
||||
SHORTINT,
|
||||
LONGINT,
|
||||
BYTE,
|
||||
EVENT,
|
||||
TIME,
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// Offloaded tracing
|
||||
|
||||
@@ -162,24 +209,29 @@ private:
|
||||
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
|
||||
// assignment operator on inserting into collections, so they don't work
|
||||
// with const fields...
|
||||
union { // The callback
|
||||
const union { // The callback
|
||||
initCb_t m_initCb;
|
||||
dumpCb_t m_dumpCb;
|
||||
dumpOffloadCb_t m_dumpOffloadCb;
|
||||
cleanupCb_t m_cleanupCb;
|
||||
};
|
||||
void* m_userp; // The user pointer to pass to the callback (the symbol table)
|
||||
const uint32_t m_fidx; // The index of the tracing function
|
||||
void* const m_userp; // The user pointer to pass to the callback (the symbol table)
|
||||
CallbackRecord(initCb_t cb, void* userp)
|
||||
: m_initCb{cb}
|
||||
, m_fidx{0}
|
||||
, m_userp{userp} {}
|
||||
CallbackRecord(dumpCb_t cb, void* userp)
|
||||
CallbackRecord(dumpCb_t cb, uint32_t fidx, void* userp)
|
||||
: m_dumpCb{cb}
|
||||
, m_fidx{fidx}
|
||||
, m_userp{userp} {}
|
||||
CallbackRecord(dumpOffloadCb_t cb, void* userp)
|
||||
CallbackRecord(dumpOffloadCb_t cb, uint32_t fidx, void* userp)
|
||||
: m_dumpOffloadCb{cb}
|
||||
, m_fidx{fidx}
|
||||
, m_userp{userp} {}
|
||||
CallbackRecord(cleanupCb_t cb, void* userp)
|
||||
: m_cleanupCb{cb}
|
||||
, m_fidx{0}
|
||||
, m_userp{userp} {}
|
||||
};
|
||||
|
||||
@@ -212,18 +264,20 @@ protected:
|
||||
private:
|
||||
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
|
||||
std::vector<CallbackRecord> m_initCbs; // Routines to initialize tracing
|
||||
std::vector<CallbackRecord> m_constCbs; // Routines to perform const dump
|
||||
std::vector<CallbackRecord> m_constOffloadCbs; // Routines to perform offloaded const dump
|
||||
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full dump
|
||||
std::vector<CallbackRecord> m_fullOffloadCbs; // Routines to perform offloaded full dump
|
||||
std::vector<CallbackRecord> m_chgCbs; // Routines to perform incremental dump
|
||||
std::vector<CallbackRecord> m_chgOffloadCbs; // Routines to perform offloaded incremental dump
|
||||
std::vector<CallbackRecord> m_cleanupCbs; // Routines to call at the end of dump
|
||||
bool m_constDump = true; // Whether a const dump is required on the next call to 'dump'
|
||||
bool m_fullDump = true; // Whether a full dump is required on the next call to 'dump'
|
||||
uint32_t m_nextCode = 0; // Next code number to assign
|
||||
uint32_t m_numSignals = 0; // Number of distinct signals
|
||||
uint32_t m_maxBits = 0; // Number of bits in the widest signal
|
||||
std::vector<std::string> m_namePrefixStack{""}; // Path prefixes to add to signal names
|
||||
// TODO: Should keep this as a Trie, that is how it's accessed all the time.
|
||||
std::vector<std::pair<int, std::string>> m_dumpvars; // dumpvar() entries
|
||||
char m_scopeEscape = '.';
|
||||
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
|
||||
double m_timeUnit = 1e-0; // Time units (ns/ms etc)
|
||||
uint64_t m_timeLastDump = 0; // Last time we did a dump
|
||||
@@ -289,6 +343,7 @@ protected:
|
||||
uint32_t nextCode() const { return m_nextCode; }
|
||||
uint32_t numSignals() const { return m_numSignals; }
|
||||
uint32_t maxBits() const { return m_maxBits; }
|
||||
void constDump(bool value) { m_constDump = value; }
|
||||
void fullDump(bool value) { m_fullDump = value; }
|
||||
|
||||
double timeRes() const { return m_timeRes; }
|
||||
@@ -298,14 +353,7 @@ protected:
|
||||
void traceInit() VL_MT_UNSAFE;
|
||||
|
||||
// Declare new signal and return true if enabled
|
||||
bool declCode(uint32_t code, const char* namep, uint32_t bits, bool tri);
|
||||
|
||||
// Is this an escape?
|
||||
bool isScopeEscape(char c) { return std::isspace(c) || c == m_scopeEscape; }
|
||||
// Character that splits scopes. Note whitespace are ALWAYS escapes.
|
||||
char scopeEscape() { return m_scopeEscape; }
|
||||
// Prefix to assume in signal declarations
|
||||
const std::string& namePrefix() const { return m_namePrefixStack.back(); }
|
||||
bool declCode(uint32_t code, const std::string& declName, uint32_t bits);
|
||||
|
||||
void closeBase();
|
||||
void flushBase();
|
||||
@@ -313,6 +361,13 @@ protected:
|
||||
bool offload() const { return m_offload; }
|
||||
bool parallel() const { return m_parallel; }
|
||||
|
||||
// Return last ' ' separated word. Assumes string does not end in ' '.
|
||||
static std::string lastWord(const std::string& str) {
|
||||
const size_t idx = str.rfind(' ');
|
||||
if (idx == std::string::npos) return str;
|
||||
return str.substr(idx + 1);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Virtual functions to be provided by the format specific implementation
|
||||
|
||||
@@ -325,7 +380,7 @@ protected:
|
||||
virtual bool preChangeDump() = 0;
|
||||
|
||||
// Trace buffer management
|
||||
virtual Buffer* getTraceBuffer() = 0;
|
||||
virtual Buffer* getTraceBuffer(uint32_t fidx) = 0;
|
||||
virtual void commitTraceBuffer(Buffer*) = 0;
|
||||
|
||||
// Configure sub-class
|
||||
@@ -359,16 +414,13 @@ public:
|
||||
|
||||
void addModel(VerilatedModel*) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
void addInitCb(initCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addConstCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
|
||||
void addConstCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
|
||||
void addFullCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
|
||||
void addFullCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
|
||||
void addChgCb(dumpCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
|
||||
void addChgCb(dumpOffloadCb_t cb, uint32_t fidx, void* userp) VL_MT_SAFE;
|
||||
void addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE;
|
||||
|
||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
||||
|
||||
void pushNamePrefix(const std::string&);
|
||||
void popNamePrefix(unsigned count = 1);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -423,7 +475,7 @@ public:
|
||||
void fullQData(uint32_t* oldp, QData newval, int bits);
|
||||
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
|
||||
void fullDouble(uint32_t* oldp, double newval);
|
||||
void fullEvent(uint32_t* oldp, VlEvent newval);
|
||||
void fullEvent(uint32_t* oldp, const VlEventBase* newval);
|
||||
|
||||
// In non-offload mode, these are called directly by the trace callbacks,
|
||||
// and are called chg*. In offload mode, they are called by the worker
|
||||
@@ -460,7 +512,9 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEvent newval) { fullEvent(oldp, newval); }
|
||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newval) {
|
||||
fullEvent(oldp, newval);
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
|
||||
double old;
|
||||
std::memcpy(&old, oldp, sizeof(old));
|
||||
@@ -539,7 +593,7 @@ public:
|
||||
m_offloadBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgEvent(uint32_t code, VlEvent newval) {
|
||||
void chgEvent(uint32_t code, const VlEventBase* newval) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
// Copyright 2001-2023 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilated tracing types
|
||||
///
|
||||
/// This file is not part of the Verilated public-facing API.
|
||||
/// It is only for internal use by Verilated tracing routines.
|
||||
///
|
||||
//=============================================================================
|
||||
#ifndef VERILATOR_VERILATED_TRACE_DEFS_H_
|
||||
#define VERILATOR_VERILATED_TRACE_DEFS_H_
|
||||
|
||||
// Verilator tracing scope types:
|
||||
// The values should match FST_ST_VCD_* from fstScopeType in gtkwave/fstapi.h
|
||||
// verilated_fst_c.cpp contains assertions to enforce this
|
||||
enum VltTraceScope {
|
||||
VLT_TRACE_SCOPE_MODULE = 0,
|
||||
VLT_TRACE_SCOPE_TASK = 1,
|
||||
VLT_TRACE_SCOPE_FUNCTION = 2,
|
||||
VLT_TRACE_SCOPE_BEGIN = 3,
|
||||
VLT_TRACE_SCOPE_FORK = 4,
|
||||
VLT_TRACE_SCOPE_GENERATE = 5,
|
||||
VLT_TRACE_SCOPE_STRUCT = 6,
|
||||
VLT_TRACE_SCOPE_UNION = 7,
|
||||
VLT_TRACE_SCOPE_CLASS = 8,
|
||||
VLT_TRACE_SCOPE_INTERFACE = 9,
|
||||
VLT_TRACE_SCOPE_PACKAGE = 10,
|
||||
VLT_TRACE_SCOPE_PROGRAM = 11
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
@@ -185,7 +185,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_EVENT:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
|
||||
traceBufp->chgEvent(oldp, *reinterpret_cast<const VlEvent*>(readp));
|
||||
traceBufp->chgEvent(oldp, reinterpret_cast<const VlEventBase*>(readp));
|
||||
continue;
|
||||
|
||||
//===
|
||||
@@ -378,13 +378,12 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||
}
|
||||
|
||||
template <>
|
||||
bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const char* namep, uint32_t bits,
|
||||
bool tri) {
|
||||
bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const std::string& declName,
|
||||
uint32_t bits) {
|
||||
if (VL_UNCOVERABLE(!code)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal");
|
||||
}
|
||||
// To keep it simple, this is O(enables * signals), but we expect few enables
|
||||
std::string declName = namePrefix() + namep;
|
||||
bool enabled = false;
|
||||
if (m_dumpvars.empty()) enabled = true;
|
||||
for (const auto& item : m_dumpvars) {
|
||||
@@ -410,10 +409,7 @@ bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const char* nam
|
||||
break;
|
||||
}
|
||||
|
||||
// Note: The tri-state flag is not used by Verilator, but is here for
|
||||
// compatibility with some foreign code.
|
||||
int codesNeeded = VL_WORDS_I(bits);
|
||||
if (tri) codesNeeded *= 2;
|
||||
m_nextCode = std::max(m_nextCode, code + codesNeeded);
|
||||
++m_numSignals;
|
||||
m_maxBits = std::max(m_maxBits, bits);
|
||||
@@ -457,7 +453,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dumpvars(int level, const std::string&
|
||||
for (auto& i : hierSpaced) {
|
||||
if (i == '.') i = ' ';
|
||||
}
|
||||
m_dumpvars.push_back(std::make_pair(level, hierSpaced));
|
||||
m_dumpvars.emplace_back(level, hierSpaced);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,16 +494,15 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<Callback
|
||||
// Main thread executes all jobs with index % threads == 0
|
||||
std::vector<ParallelWorkerData*> mainThreadWorkerData;
|
||||
// Enqueue all the jobs
|
||||
for (unsigned i = 0; i < cbVec.size(); ++i) {
|
||||
const CallbackRecord& cbr = cbVec[i];
|
||||
for (const CallbackRecord& cbr : cbVec) {
|
||||
// Always get the trace buffer on the main thread
|
||||
Buffer* const bufp = getTraceBuffer();
|
||||
Buffer* const bufp = getTraceBuffer(cbr.m_fidx);
|
||||
// Create new work item
|
||||
workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp);
|
||||
// Grab the new work item
|
||||
ParallelWorkerData* const itemp = &workerData.back();
|
||||
// Enqueue task to thread pool, or main thread
|
||||
if (unsigned rem = i % threads) {
|
||||
if (unsigned rem = cbr.m_fidx % threads) {
|
||||
threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp);
|
||||
} else {
|
||||
mainThreadWorkerData.push_back(itemp);
|
||||
@@ -530,7 +525,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<Callback
|
||||
}
|
||||
// Fall back on sequential execution
|
||||
for (const CallbackRecord& cbr : cbVec) {
|
||||
Buffer* const traceBufferp = getTraceBuffer();
|
||||
Buffer* const traceBufferp = getTraceBuffer(cbr.m_fidx);
|
||||
cbr.m_dumpCb(cbr.m_userp, traceBufferp);
|
||||
commitTraceBuffer(traceBufferp);
|
||||
}
|
||||
@@ -541,7 +536,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runOffloadedCallbacks(
|
||||
const std::vector<CallbackRecord>& cbVec) {
|
||||
// Fall back on sequential execution
|
||||
for (const CallbackRecord& cbr : cbVec) {
|
||||
Buffer* traceBufferp = getTraceBuffer();
|
||||
Buffer* traceBufferp = getTraceBuffer(cbr.m_fidx);
|
||||
cbr.m_dumpOffloadCb(cbr.m_userp, static_cast<OffloadBuffer*>(traceBufferp));
|
||||
commitTraceBuffer(traceBufferp);
|
||||
}
|
||||
@@ -610,6 +605,15 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
|
||||
}
|
||||
}
|
||||
|
||||
if (VL_UNLIKELY(m_constDump)) {
|
||||
m_constDump = false;
|
||||
if (offload()) {
|
||||
runOffloadedCallbacks(m_constOffloadCbs);
|
||||
} else {
|
||||
runCallbacks(m_constCbs);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
|
||||
const CallbackRecord& cbr = m_cleanupCbs[i];
|
||||
cbr.m_cleanupCb(cbr.m_userp, self());
|
||||
@@ -695,37 +699,40 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addInitCb(initCb_t cb, void* userp) VL_
|
||||
addCallbackRecord(m_initCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_fullCbs, CallbackRecord{cb, userp});
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addConstCb(dumpCb_t cb, uint32_t fidx,
|
||||
void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_constCbs, CallbackRecord{cb, fidx, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, userp});
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addConstCb(dumpOffloadCb_t cb, uint32_t fidx,
|
||||
void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_constOffloadCbs, CallbackRecord{cb, fidx, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_chgCbs, CallbackRecord{cb, userp});
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, uint32_t fidx,
|
||||
void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_fullCbs, CallbackRecord{cb, fidx, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, userp});
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpOffloadCb_t cb, uint32_t fidx,
|
||||
void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, fidx, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, uint32_t fidx,
|
||||
void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_chgCbs, CallbackRecord{cb, fidx, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpOffloadCb_t cb, uint32_t fidx,
|
||||
void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, fidx, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_cleanupCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::pushNamePrefix(const std::string& prefix) {
|
||||
m_namePrefixStack.push_back(m_namePrefixStack.back() + prefix);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::popNamePrefix(unsigned count) {
|
||||
while (count--) m_namePrefixStack.pop_back();
|
||||
assert(!m_namePrefixStack.empty());
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Primitives converting binary values to strings...
|
||||
|
||||
@@ -839,7 +846,7 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, VlEvent newval) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newval) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = 1; // Do we really store an "event" ?
|
||||
emitEvent(code, newval);
|
||||
|
||||
+162
-17
@@ -33,6 +33,7 @@
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
@@ -69,16 +70,28 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
|
||||
#define VL_INOUTW(name, msb, lsb, words) VlWide<words> name ///< Declare bidir signal, 65+ bits
|
||||
#define VL_OUT8(name, msb, lsb) CData name ///< Declare output signal, 1-8 bits
|
||||
#define VL_OUT16(name, msb, lsb) SData name ///< Declare output signal, 9-16 bits
|
||||
#define VL_OUT64(name, msb, lsb) QData name ///< Declare output signal, 33-64bits
|
||||
#define VL_OUT64(name, msb, lsb) QData name ///< Declare output signal, 33-64 bits
|
||||
#define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits
|
||||
#define VL_OUTW(name, msb, lsb, words) VlWide<words> name ///< Declare output signal, 65+ bits
|
||||
|
||||
//===================================================================
|
||||
// VlProcess stores metadata of running processes
|
||||
// Functions needed here
|
||||
|
||||
constexpr IData VL_CLOG2_CE_Q(QData lhs) VL_PURE {
|
||||
// constexpr usage only! Recuses to meet C++11 constexpr func limitations
|
||||
return lhs <= 1 ? 0 : VL_CLOG2_CE_Q((lhs + 1) >> 1ULL) + 1;
|
||||
}
|
||||
|
||||
// Metadata of processes
|
||||
class VlProcess;
|
||||
|
||||
using VlProcessRef = std::shared_ptr<VlProcess>;
|
||||
|
||||
class VlProcess final {
|
||||
// MEMBERS
|
||||
int m_state; // Current state of the process
|
||||
VlProcessRef m_parentp = nullptr; // Parent process, if exists
|
||||
std::set<VlProcess*> m_children; // Active child processes
|
||||
|
||||
public:
|
||||
// TYPES
|
||||
@@ -91,16 +104,40 @@ public:
|
||||
};
|
||||
|
||||
// CONSTRUCTORS
|
||||
// Construct independent process
|
||||
VlProcess()
|
||||
: m_state{RUNNING} {}
|
||||
// Construct child process of parent
|
||||
VlProcess(VlProcessRef parentp)
|
||||
: m_state{RUNNING}
|
||||
, m_parentp{parentp} {
|
||||
m_parentp->attach(this);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
int state() { return m_state; }
|
||||
~VlProcess() {
|
||||
if (m_parentp) m_parentp->detach(this);
|
||||
}
|
||||
|
||||
void attach(VlProcess* childp) { m_children.insert(childp); }
|
||||
void detach(VlProcess* childp) { m_children.erase(childp); }
|
||||
|
||||
int state() const { return m_state; }
|
||||
void state(int s) { m_state = s; }
|
||||
void disable() {
|
||||
state(KILLED);
|
||||
disableFork();
|
||||
}
|
||||
void disableFork() {
|
||||
for (VlProcess* childp : m_children) childp->disable();
|
||||
}
|
||||
bool completed() const { return state() == FINISHED || state() == KILLED; }
|
||||
bool completedFork() const {
|
||||
for (const VlProcess* const childp : m_children)
|
||||
if (!childp->completed()) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
using VlProcessRef = std::shared_ptr<VlProcess>;
|
||||
|
||||
inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); }
|
||||
|
||||
//===================================================================
|
||||
@@ -155,7 +192,18 @@ public:
|
||||
//===================================================================
|
||||
// SystemVerilog event type
|
||||
|
||||
class VlEvent final {
|
||||
class VlEventBase VL_NOT_FINAL {
|
||||
public:
|
||||
virtual ~VlEventBase() = default;
|
||||
|
||||
virtual void fire() = 0;
|
||||
virtual bool isFired() const = 0;
|
||||
virtual bool isTriggered() const = 0;
|
||||
virtual void clearFired() = 0;
|
||||
virtual void clearTriggered() = 0;
|
||||
};
|
||||
|
||||
class VlEvent final : public VlEventBase {
|
||||
// MEMBERS
|
||||
bool m_fired = false; // Fired on this scheduling iteration
|
||||
bool m_triggered = false; // Triggered state of event persisting until next time step
|
||||
@@ -163,20 +211,50 @@ class VlEvent final {
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
VlEvent() = default;
|
||||
~VlEvent() = default;
|
||||
~VlEvent() override = default;
|
||||
|
||||
friend std::string VL_TO_STRING(const VlEvent& e);
|
||||
friend class VlAssignableEvent;
|
||||
// METHODS
|
||||
void fire() { m_fired = m_triggered = true; }
|
||||
bool isFired() const { return m_fired; }
|
||||
bool isTriggered() const { return m_triggered; }
|
||||
void clearFired() { m_fired = false; }
|
||||
void clearTriggered() { m_triggered = false; }
|
||||
void fire() override { m_fired = m_triggered = true; }
|
||||
bool isFired() const override { return m_fired; }
|
||||
bool isTriggered() const override { return m_triggered; }
|
||||
void clearFired() override { m_fired = false; }
|
||||
void clearTriggered() override { m_triggered = false; }
|
||||
};
|
||||
|
||||
class VlAssignableEvent final : public std::shared_ptr<VlEvent>, public VlEventBase {
|
||||
public:
|
||||
// Constructor
|
||||
VlAssignableEvent()
|
||||
: std::shared_ptr<VlEvent>(new VlEvent) {}
|
||||
~VlAssignableEvent() override = default;
|
||||
|
||||
// METHODS
|
||||
void fire() override { (*this)->m_fired = (*this)->m_triggered = true; }
|
||||
bool isFired() const override { return (*this)->m_fired; }
|
||||
bool isTriggered() const override { return (*this)->m_triggered; }
|
||||
void clearFired() override { (*this)->m_fired = false; }
|
||||
void clearTriggered() override { (*this)->m_triggered = false; }
|
||||
};
|
||||
|
||||
inline std::string VL_TO_STRING(const VlEventBase& e);
|
||||
|
||||
inline std::string VL_TO_STRING(const VlEvent& e) {
|
||||
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
|
||||
}
|
||||
|
||||
inline std::string VL_TO_STRING(const VlAssignableEvent& e) {
|
||||
return "&{ " + VL_TO_STRING(*e) + " }";
|
||||
}
|
||||
|
||||
inline std::string VL_TO_STRING(const VlEventBase& e) {
|
||||
if (const VlAssignableEvent& assignable = dynamic_cast<const VlAssignableEvent&>(e)) {
|
||||
return VL_TO_STRING(assignable);
|
||||
}
|
||||
return std::string{"triggered="} + (e.isTriggered() ? "true" : "false");
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Random
|
||||
|
||||
@@ -210,6 +288,58 @@ public:
|
||||
size_t operator()() { return VL_MASK_I(31) & vl_rand64(); }
|
||||
};
|
||||
|
||||
template <class T_Value, uint64_t T_numValues>
|
||||
class VlRandC final {
|
||||
T_Value m_remaining = 0; // Number of values to pull before re-randomize
|
||||
T_Value m_lfsr = 1; // LFSR state
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlRandC() {
|
||||
static_assert(T_numValues >= 1, "");
|
||||
static_assert(sizeof(T_Value) == 8 || (T_numValues < (1ULL << (8 * sizeof(T_Value)))), "");
|
||||
}
|
||||
// METHODS
|
||||
T_Value randomize(VlRNG& rngr) {
|
||||
if (VL_UNLIKELY(!m_remaining)) reseed(rngr);
|
||||
// Polynomials are first listed at https://users.ece.cmu.edu/~koopman/lfsr/
|
||||
static constexpr uint64_t s_polynomials[] = {
|
||||
0x0ULL, // 0 never used (constant, no randomization)
|
||||
0x0ULL, // 1
|
||||
0x3ULL, 0x5ULL, 0x9ULL, 0x12ULL, 0x21ULL,
|
||||
0x41ULL, 0x8eULL, 0x108ULL, 0x204ULL, 0x402ULL,
|
||||
0x829ULL, 0x100dULL, 0x2015ULL, 0x4001ULL,
|
||||
0x8016ULL, // 16
|
||||
0x10004ULL, 0x20040ULL, 0x40013ULL, 0x80004ULL, 0x100002ULL,
|
||||
0x200001ULL, 0x400010ULL, 0x80000dULL, 0x1000004ULL, 0x2000023ULL,
|
||||
0x4000013ULL, 0x8000004ULL, 0x10000002ULL, 0x20000029ULL, 0x40000004ULL,
|
||||
0x80000057ULL, // 32
|
||||
0x100000029ULL // 33
|
||||
};
|
||||
constexpr uint32_t clogWidth = VL_CLOG2_CE_Q(T_numValues) + 1;
|
||||
constexpr uint32_t lfsrWidth = (clogWidth < 2) ? 2 : clogWidth;
|
||||
constexpr T_Value polynomial = static_cast<T_Value>(s_polynomials[lfsrWidth]);
|
||||
// printf(" numV=%ld w=%d poly=%x\n", T_numValues, lfsrWidth, polynomial);
|
||||
// Loop until get reasonable value. Because we picked a LFSR of at most one
|
||||
// extra bit in width, this will only require at most on average 1.5 loops
|
||||
do {
|
||||
m_lfsr = (m_lfsr & 1ULL) ? ((m_lfsr >> 1ULL) ^ polynomial) : (m_lfsr >> 1ULL);
|
||||
} while (m_lfsr > T_numValues); // Note if == then output value 0
|
||||
--m_remaining;
|
||||
T_Value result = (m_lfsr == T_numValues) ? 0 : m_lfsr;
|
||||
// printf(" result=%x (numv=%ld, rem=%d)\n", result, T_numValues, m_remaining);
|
||||
return result;
|
||||
}
|
||||
void reseed(VlRNG& rngr) {
|
||||
constexpr uint32_t lfsrWidth = VL_CLOG2_CE_Q(T_numValues) + 1;
|
||||
m_remaining = T_numValues;
|
||||
do {
|
||||
m_lfsr = rngr.rand64() & VL_MASK_Q(lfsrWidth);
|
||||
// printf(" lfsr.reseed=%x\n", m_lfsr);
|
||||
} while (!m_lfsr); // 0 not a legal seed
|
||||
}
|
||||
};
|
||||
|
||||
// These require the class object to have the thread safety lock
|
||||
inline IData VL_RANDOM_RNG_I(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
|
||||
inline QData VL_RANDOM_RNG_Q(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); }
|
||||
@@ -457,7 +587,7 @@ public:
|
||||
|
||||
// function void q.insert(index, value);
|
||||
void insert(int32_t index, const T_Value& value) {
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return;
|
||||
if (VL_UNLIKELY(index < 0 || index > m_deque.size())) return;
|
||||
m_deque.insert(m_deque.begin() + index, value);
|
||||
}
|
||||
|
||||
@@ -1418,8 +1548,8 @@ class VlClass VL_NOT_FINAL : public VlDeletable {
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlClass() = default;
|
||||
VlClass(const VlClass& copied) {}
|
||||
VlClass() { refCountInc(); }
|
||||
VlClass(const VlClass& copied) { refCountInc(); }
|
||||
~VlClass() override = default;
|
||||
};
|
||||
|
||||
@@ -1467,8 +1597,9 @@ public:
|
||||
// () required here to avoid narrowing conversion warnings,
|
||||
// when a new() has an e.g. CData type and passed a 1U.
|
||||
: m_objp{new T_Class(std::forward<T_Args>(args)...)} {
|
||||
// refCountInc was moved to the constructor of T_Class
|
||||
// to fix self references in constructor.
|
||||
m_objp->m_deleterp = &deleter;
|
||||
refCountInc();
|
||||
}
|
||||
// Explicit to avoid implicit conversion from 0
|
||||
explicit VlClassRef(T_Class* objp)
|
||||
@@ -1546,10 +1677,18 @@ public:
|
||||
bool operator!=(const VlClassRef<T_OtherClass>& rhs) const {
|
||||
return m_objp != rhs.m_objp;
|
||||
};
|
||||
template <typename T_OtherClass>
|
||||
bool operator<(const VlClassRef<T_OtherClass>& rhs) const {
|
||||
return m_objp < rhs.m_objp;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
|
||||
if (!in) {
|
||||
outr = VlNull{};
|
||||
return true;
|
||||
}
|
||||
VlClassRef<U> casted = in.template dynamicCast<U>();
|
||||
if (VL_LIKELY(casted)) {
|
||||
outr = casted;
|
||||
@@ -1559,6 +1698,12 @@ static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool VL_CAST_DYNAMIC(VlNull in, VlClassRef<T>& outr) {
|
||||
outr = VlNull{};
|
||||
return true;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VlSampleQueue stores samples for input clockvars in clocking blocks. At a clocking event,
|
||||
// samples from this queue should be written to the correct input clockvar.
|
||||
|
||||
+124
-219
@@ -112,7 +112,19 @@ void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
openNextImp(m_rolloverSize != 0);
|
||||
if (!isOpen()) return;
|
||||
|
||||
dumpHeader();
|
||||
printStr("$version Generated by VerilatedVcd $end\n");
|
||||
printStr("$timescale ");
|
||||
printStr(timeResStr().c_str()); // lintok-begin-on-ref
|
||||
printStr(" $end\n");
|
||||
|
||||
// Scope and signal definitions
|
||||
assert(m_indent == 0);
|
||||
++m_indent;
|
||||
Super::traceInit();
|
||||
--m_indent;
|
||||
assert(m_indent == 0);
|
||||
|
||||
printStr("$enddefinitions $end\n\n\n");
|
||||
|
||||
// When using rollover, the first chunk contains the header only.
|
||||
if (m_rolloverSize) openNextImp(true);
|
||||
@@ -164,6 +176,7 @@ void VerilatedVcd::openNextImp(bool incFilename) {
|
||||
}
|
||||
}
|
||||
m_isOpen = true;
|
||||
constDump(true); // First dump must containt the const signals
|
||||
fullDump(true); // First dump must be full
|
||||
m_wroteBytes = 0;
|
||||
}
|
||||
@@ -175,49 +188,14 @@ bool VerilatedVcd::preChangeDump() {
|
||||
|
||||
void VerilatedVcd::emitTimeChange(uint64_t timeui) {
|
||||
printStr("#");
|
||||
printQuad(timeui);
|
||||
const std::string str = std::to_string(timeui);
|
||||
printStr(str.c_str());
|
||||
printStr("\n");
|
||||
}
|
||||
|
||||
void VerilatedVcd::makeNameMap() {
|
||||
// Take signal information from each module and build m_namemapp
|
||||
deleteNameMap();
|
||||
m_namemapp = new NameMap;
|
||||
|
||||
Super::traceInit();
|
||||
|
||||
// Though not speced, it's illegal to generate a vcd with signals
|
||||
// not under any module - it crashes at least two viewers.
|
||||
// If no scope was specified, prefix everything with a "top"
|
||||
// This comes from user instantiations with no name - IE Vtop("").
|
||||
bool nullScope = false;
|
||||
for (const auto& i : *m_namemapp) {
|
||||
const std::string& hiername = i.first;
|
||||
if (!hiername.empty() && hiername[0] == '\t') nullScope = true;
|
||||
}
|
||||
if (nullScope) {
|
||||
NameMap* const newmapp = new NameMap;
|
||||
for (const auto& i : *m_namemapp) {
|
||||
const std::string& hiername = i.first;
|
||||
const std::string& decl = i.second;
|
||||
std::string newname{"top"};
|
||||
if (hiername[0] != '\t') newname += ' ';
|
||||
newname += hiername;
|
||||
newmapp->emplace(newname, decl);
|
||||
}
|
||||
deleteNameMap();
|
||||
m_namemapp = newmapp;
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::deleteNameMap() {
|
||||
if (m_namemapp) VL_DO_CLEAR(delete m_namemapp, m_namemapp = nullptr);
|
||||
}
|
||||
|
||||
VerilatedVcd::~VerilatedVcd() {
|
||||
close();
|
||||
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = nullptr);
|
||||
deleteNameMap();
|
||||
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = nullptr);
|
||||
if (parallel()) {
|
||||
assert(m_numBuffers == m_freeBuffers.size());
|
||||
@@ -270,13 +248,6 @@ void VerilatedVcd::printStr(const char* str) {
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::printQuad(uint64_t n) {
|
||||
constexpr size_t LEN_STR_QUAD = 40;
|
||||
char buf[LEN_STR_QUAD];
|
||||
VL_SNPRINTF(buf, LEN_STR_QUAD, "%" PRIu64, n);
|
||||
printStr(buf);
|
||||
}
|
||||
|
||||
void VerilatedVcd::bufferResize(size_t minsize) {
|
||||
// minsize is size of largest write. We buffer at least 8 times as much data,
|
||||
// writing when we are 3/4 full (with thus 2*minsize remaining free)
|
||||
@@ -325,127 +296,59 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
|
||||
m_writep = m_wrBufp;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VCD string code
|
||||
|
||||
char* VerilatedVcd::writeCode(char* writep, uint32_t code) {
|
||||
*writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
while (code) {
|
||||
--code;
|
||||
*writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
}
|
||||
return writep;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Definitions
|
||||
|
||||
void VerilatedVcd::printIndent(int level_change) {
|
||||
if (level_change < 0) m_modDepth += level_change;
|
||||
assert(m_modDepth >= 0);
|
||||
for (int i = 0; i < m_modDepth; i++) printStr(" ");
|
||||
if (level_change > 0) m_modDepth += level_change;
|
||||
if (level_change < 0) m_indent += level_change;
|
||||
for (int i = 0; i < m_indent; i++) printStr(" ");
|
||||
if (level_change > 0) m_indent += level_change;
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpHeader() {
|
||||
printStr("$version Generated by VerilatedVcd $end\n");
|
||||
|
||||
// Verilator used to put in a $date here. Although $date is shown in
|
||||
// IEEE examples, and it is common in VCD writers, VCD readers don't
|
||||
// seem to care about it. Thus, we omit the $date so artifacts are
|
||||
// more likely to be reproducible. If use cases show up that require
|
||||
// the $date command to be present, it could be re-added with support
|
||||
// for the SOURCE_DATE_EPOCH hook.
|
||||
|
||||
printStr("$timescale ");
|
||||
printStr(timeResStr().c_str()); // lintok-begin-on-ref
|
||||
printStr(" $end\n");
|
||||
|
||||
makeNameMap();
|
||||
|
||||
// Signal header
|
||||
assert(m_modDepth == 0);
|
||||
printIndent(1);
|
||||
printStr("\n");
|
||||
|
||||
// We detect the spaces in module names to determine hierarchy. This
|
||||
// allows signals to be declared without fixed ordering, which is
|
||||
// required as Verilog signals might be separately declared from
|
||||
// SC module signals.
|
||||
|
||||
// Print the signal names
|
||||
const char* lastName = "";
|
||||
for (const auto& i : *m_namemapp) {
|
||||
const std::string& hiernamestr = i.first;
|
||||
const std::string& decl = i.second;
|
||||
|
||||
// Determine difference between the old and new names
|
||||
const char* const hiername = hiernamestr.c_str();
|
||||
const char* lp = lastName;
|
||||
const char* np = hiername;
|
||||
lastName = hiername;
|
||||
|
||||
// Skip common prefix, it must break at a space or tab
|
||||
for (; *np && (*np == *lp); np++, lp++) {}
|
||||
while (np != hiername && *np && *np != ' ' && *np != '\t') {
|
||||
--np;
|
||||
--lp;
|
||||
}
|
||||
// printf("hier %s\n lp=%s\n np=%s\n",hiername,lp,np);
|
||||
|
||||
// Any extra spaces in last name are scope ups we need to do
|
||||
bool first = true;
|
||||
for (; *lp; lp++) {
|
||||
if (*lp == ' ' || (first && *lp != '\t')) {
|
||||
printIndent(-1);
|
||||
printStr("$upscope $end\n");
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
// Any new spaces are scope downs we need to do
|
||||
while (*np) {
|
||||
if (*np == ' ') np++;
|
||||
if (*np == '\t') break; // tab means signal name starts
|
||||
printIndent(1);
|
||||
printStr("$scope module ");
|
||||
|
||||
for (; *np && *np != ' ' && *np != '\t'; np++) {
|
||||
if (*np == '[') {
|
||||
printStr("[");
|
||||
} else if (*np == ']') {
|
||||
printStr("]");
|
||||
} else {
|
||||
*m_writep++ = *np;
|
||||
}
|
||||
}
|
||||
printStr(" $end\n");
|
||||
}
|
||||
|
||||
printIndent(0);
|
||||
printStr(decl.c_str());
|
||||
void VerilatedVcd::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
|
||||
std::string newPrefix = m_prefixStack.back().first + name;
|
||||
switch (type) {
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
case VerilatedTracePrefixType::STRUCT_UNPACKED:
|
||||
case VerilatedTracePrefixType::UNION_PACKED: {
|
||||
printIndent(1);
|
||||
printStr("$scope module ");
|
||||
const std::string n = lastWord(newPrefix);
|
||||
printStr(n.c_str());
|
||||
printStr(" $end\n");
|
||||
newPrefix += ' ';
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
m_prefixStack.emplace_back(newPrefix, type);
|
||||
}
|
||||
|
||||
while (m_modDepth > 1) {
|
||||
void VerilatedVcd::popPrefix() {
|
||||
switch (m_prefixStack.back().second) {
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
case VerilatedTracePrefixType::STRUCT_UNPACKED:
|
||||
case VerilatedTracePrefixType::UNION_PACKED:
|
||||
printIndent(-1);
|
||||
printStr("$upscope $end\n");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
printIndent(-1);
|
||||
printStr("$enddefinitions $end\n\n\n");
|
||||
assert(m_modDepth == 0);
|
||||
|
||||
// Reclaim storage
|
||||
deleteNameMap();
|
||||
m_prefixStack.pop_back();
|
||||
assert(!m_prefixStack.empty());
|
||||
}
|
||||
|
||||
void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, bool array,
|
||||
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
||||
int arraynum, bool bussed, int msb, int lsb) {
|
||||
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||
|
||||
const bool enabled = Super::declCode(code, name, bits, tri);
|
||||
const std::string hierarchicalName = m_prefixStack.back().first + name;
|
||||
|
||||
const bool enabled = Super::declCode(code, hierarchicalName, bits);
|
||||
|
||||
if (m_suffixes.size() <= nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE) {
|
||||
m_suffixes.resize(nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0);
|
||||
@@ -458,93 +361,95 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b
|
||||
|
||||
if (!enabled) return;
|
||||
|
||||
// Split name into basename
|
||||
// Spaces and tabs aren't legal in VCD signal names, so:
|
||||
// Space separates each level of scope
|
||||
// Tab separates final scope from signal name
|
||||
// Tab sorts before spaces, so signals nicely will print before scopes
|
||||
// Note the hiername may be nothing, if so we'll add "\t{name}"
|
||||
std::string nameasstr = namePrefix() + name;
|
||||
std::string hiername;
|
||||
std::string basename;
|
||||
for (const char* cp = nameasstr.c_str(); *cp; cp++) {
|
||||
if (isScopeEscape(*cp)) {
|
||||
// Ahh, we've just read a scope, not a basename
|
||||
if (!hiername.empty()) hiername += " ";
|
||||
hiername += basename;
|
||||
basename = "";
|
||||
} else {
|
||||
basename += *cp;
|
||||
}
|
||||
// Create the VCD code and build the suffix array entry
|
||||
char vcdCode[VL_TRACE_SUFFIX_ENTRY_SIZE];
|
||||
{
|
||||
// Render the VCD code
|
||||
char* vcdCodeWritep = vcdCode;
|
||||
uint32_t codeEnc = code;
|
||||
do {
|
||||
*vcdCodeWritep++ = static_cast<char>('!' + codeEnc % 94);
|
||||
codeEnc /= 94;
|
||||
} while (codeEnc--);
|
||||
*vcdCodeWritep = '\0';
|
||||
const size_t vcdCodeLength = vcdCodeWritep - vcdCode;
|
||||
assert(vcdCodeLength <= VL_TRACE_MAX_VCD_CODE_SIZE);
|
||||
// Build suffix array entry
|
||||
char* const entryBeginp = &m_suffixes[code * VL_TRACE_SUFFIX_ENTRY_SIZE];
|
||||
entryBeginp[0] = ' '; // Separator
|
||||
// 1 bit values don't have a ' ' separator between value and string code
|
||||
char* entryWritep = bits == 1 ? entryBeginp : entryBeginp + 1;
|
||||
// Use memcpy as we know the size, and strcpy is flagged unsafe
|
||||
std::memcpy(entryWritep, vcdCode, vcdCodeLength);
|
||||
entryWritep += vcdCodeLength;
|
||||
// Line terminator
|
||||
*entryWritep++ = '\n';
|
||||
// Set length of suffix (used to increment write pointer)
|
||||
assert(entryWritep <= entryBeginp + VL_TRACE_SUFFIX_ENTRY_SIZE - 1);
|
||||
entryBeginp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1] = static_cast<char>(entryWritep - entryBeginp);
|
||||
}
|
||||
hiername += "\t" + basename;
|
||||
|
||||
// Print reference
|
||||
// Assemble the declaration
|
||||
std::string decl = "$var ";
|
||||
decl += wirep; // usually "wire"
|
||||
|
||||
constexpr size_t bufsize = 1000;
|
||||
char buf[bufsize];
|
||||
VL_SNPRINTF(buf, bufsize, " %2d ", bits);
|
||||
decl += buf;
|
||||
// Add string code to decl
|
||||
char* const endp = writeCode(buf, code);
|
||||
*endp = '\0';
|
||||
decl += buf;
|
||||
// Build suffix array entry
|
||||
char* const entryp = &m_suffixes[code * VL_TRACE_SUFFIX_ENTRY_SIZE];
|
||||
const size_t length = endp - buf;
|
||||
assert(length <= VL_TRACE_MAX_VCD_CODE_SIZE);
|
||||
// 1 bit values don't have a ' ' separator between value and string code
|
||||
const bool isBit = bits == 1;
|
||||
entryp[0] = ' '; // Separator
|
||||
// Use memcpy as we checked size above, and strcpy is flagged unsafe
|
||||
std::memcpy(entryp + !isBit, buf,
|
||||
std::strlen(buf)); // Code (overwrite separator if isBit)
|
||||
entryp[length + !isBit] = '\n'; // Replace '\0' with line termination '\n'
|
||||
// Set length of suffix (used to increment write pointer)
|
||||
entryp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1] = static_cast<char>(length + !isBit + 1);
|
||||
decl += " ";
|
||||
decl += basename;
|
||||
decl += wirep;
|
||||
decl += ' ';
|
||||
decl += std::to_string(bits);
|
||||
decl += ' ';
|
||||
decl += vcdCode;
|
||||
decl += ' ';
|
||||
decl += lastWord(hierarchicalName);
|
||||
if (array) {
|
||||
VL_SNPRINTF(buf, bufsize, "[%d]", arraynum);
|
||||
decl += buf;
|
||||
hiername += buf;
|
||||
decl += '[';
|
||||
decl += std::to_string(arraynum);
|
||||
decl += ']';
|
||||
}
|
||||
if (bussed) {
|
||||
VL_SNPRINTF(buf, bufsize, " [%d:%d]", msb, lsb);
|
||||
decl += buf;
|
||||
decl += " [";
|
||||
decl += std::to_string(msb);
|
||||
decl += ':';
|
||||
decl += std::to_string(lsb);
|
||||
decl += ']';
|
||||
}
|
||||
decl += " $end\n";
|
||||
m_namemapp->emplace(hiername, decl);
|
||||
printIndent(0);
|
||||
printStr(decl.c_str());
|
||||
}
|
||||
|
||||
void VerilatedVcd::declEvent(uint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "event", array, arraynum, false, false, 0, 0);
|
||||
void VerilatedVcd::declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind,
|
||||
VerilatedTraceSigType, bool array, int arraynum) {
|
||||
declare(code, name, "event", array, arraynum, false, 0, 0);
|
||||
}
|
||||
void VerilatedVcd::declBit(uint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "wire", array, arraynum, false, false, 0, 0);
|
||||
void VerilatedVcd::declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind,
|
||||
VerilatedTraceSigType, bool array, int arraynum) {
|
||||
declare(code, name, "wire", array, arraynum, false, 0, 0);
|
||||
}
|
||||
void VerilatedVcd::declBus(uint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||
int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
|
||||
void VerilatedVcd::declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind,
|
||||
VerilatedTraceSigType, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedVcd::declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||
int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
|
||||
void VerilatedVcd::declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind,
|
||||
VerilatedTraceSigType, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedVcd::declArray(uint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||
int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
|
||||
void VerilatedVcd::declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind,
|
||||
VerilatedTraceSigType, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, true, msb, lsb);
|
||||
}
|
||||
void VerilatedVcd::declDouble(uint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "real", array, arraynum, false, false, 63, 0);
|
||||
void VerilatedVcd::declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind,
|
||||
VerilatedTraceSigType, bool array, int arraynum) {
|
||||
declare(code, name, "real", array, arraynum, false, 63, 0);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Get/commit trace buffer
|
||||
|
||||
VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer() {
|
||||
VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer(uint32_t fidx) {
|
||||
VerilatedVcd::Buffer* const bufp = new Buffer{*this};
|
||||
if (parallel()) {
|
||||
// Note: This is called from VerilatedVcd::dump, which already holds the lock
|
||||
@@ -669,8 +574,8 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
|
||||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedVcdBuffer::emitEvent(uint32_t code, VlEvent newval) {
|
||||
const bool triggered = newval.isTriggered();
|
||||
void VerilatedVcdBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
|
||||
const bool triggered = newval->isTriggered();
|
||||
// TODO : It seems that untriggered events are not filtered
|
||||
// should be tested before this last step
|
||||
if (triggered) {
|
||||
|
||||
+28
-21
@@ -24,7 +24,6 @@
|
||||
#include "verilated.h"
|
||||
#include "verilated_trace.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -51,7 +50,7 @@ private:
|
||||
bool m_isOpen = false; // True indicates open file
|
||||
std::string m_filename; // Filename we're writing to (if open)
|
||||
uint64_t m_rolloverSize = 0; // File size to rollover at
|
||||
int m_modDepth = 0; // Depth of module hierarchy
|
||||
unsigned m_indent = 0; // Indentation depth
|
||||
|
||||
char* m_wrBufp; // Output buffer
|
||||
char* m_wrFlushp; // Output buffer flush trigger location
|
||||
@@ -62,8 +61,9 @@ private:
|
||||
|
||||
std::vector<char> m_suffixes; // VCD line end string codes + metadata
|
||||
|
||||
using NameMap = std::map<const std::string, const std::string>;
|
||||
NameMap* m_namemapp = nullptr; // List of names for the header
|
||||
// Prefixes to add to signal names/scope types
|
||||
std::vector<std::pair<std::string, VerilatedTracePrefixType>> m_prefixStack{
|
||||
{"", VerilatedTracePrefixType::SCOPE_MODULE}};
|
||||
|
||||
// Vector of free trace buffers as (pointer, size) pairs.
|
||||
std::vector<std::pair<char*, size_t>> m_freeBuffers;
|
||||
@@ -79,18 +79,10 @@ private:
|
||||
void openNextImp(bool incFilename);
|
||||
void closePrev();
|
||||
void closeErr();
|
||||
void makeNameMap();
|
||||
void deleteNameMap();
|
||||
void printIndent(int level_change);
|
||||
void printStr(const char* str);
|
||||
void printQuad(uint64_t n);
|
||||
void printTime(uint64_t timeui);
|
||||
void declare(uint32_t code, const char* name, const char* wirep, bool array, int arraynum,
|
||||
bool tri, bool bussed, int msb, int lsb);
|
||||
|
||||
void dumpHeader();
|
||||
|
||||
static char* writeCode(char* writep, uint32_t code);
|
||||
bool bussed, int msb, int lsb);
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcd);
|
||||
@@ -107,7 +99,7 @@ protected:
|
||||
bool preChangeDump() override;
|
||||
|
||||
// Trace buffer management
|
||||
Buffer* getTraceBuffer() override;
|
||||
Buffer* getTraceBuffer(uint32_t fidx) override;
|
||||
void commitTraceBuffer(Buffer*) override;
|
||||
|
||||
// Configure sub-class
|
||||
@@ -140,12 +132,27 @@ public:
|
||||
//=========================================================================
|
||||
// Internal interface to Verilator generated code
|
||||
|
||||
void declEvent(uint32_t code, const char* name, bool array, int arraynum);
|
||||
void declBit(uint32_t code, const char* name, bool array, int arraynum);
|
||||
void declBus(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declArray(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declDouble(uint32_t code, const char* name, bool array, int arraynum);
|
||||
void pushPrefix(const std::string&, VerilatedTracePrefixType);
|
||||
void popPrefix();
|
||||
|
||||
void declEvent(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum);
|
||||
void declBit(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum);
|
||||
void declBus(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum, int msb, int lsb);
|
||||
void declArray(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum, int msb, int lsb);
|
||||
void declDouble(uint32_t code, uint32_t fidx, const char* name, int dtypenum,
|
||||
VerilatedTraceSigDirection, VerilatedTraceSigKind, VerilatedTraceSigType,
|
||||
bool array, int arraynum);
|
||||
};
|
||||
|
||||
#ifndef DOXYGEN
|
||||
@@ -207,7 +214,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
|
||||
// Implementation of VerilatedTraceBuffer interface
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
|
||||
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||
|
||||
+253
-16
@@ -303,7 +303,13 @@ public:
|
||||
uint32_t entSize() const { return m_entSize; }
|
||||
uint32_t index() const { return m_index; }
|
||||
uint32_t type() const override {
|
||||
return (varp()->dims() > 1) ? vpiMemory : vpiReg; // but might be wire, logic
|
||||
uint32_t type = vpiReg;
|
||||
switch (varp()->vltype()) {
|
||||
case VLVT_REAL: type = vpiRealVar; break;
|
||||
case VLVT_STRING: type = vpiStringVar; break;
|
||||
default: break;
|
||||
}
|
||||
return (varp()->dims() > 1) ? vpiMemory : type; // but might be wire, logic
|
||||
}
|
||||
void* prevDatap() const { return m_prevDatap; }
|
||||
void* varDatap() const { return m_varDatap; }
|
||||
@@ -536,8 +542,7 @@ public:
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb reason=%d id=%" PRId64 " time=%" PRIu64
|
||||
" obj=%p\n",
|
||||
cb_data_p->reason, id, time, cb_data_p->obj););
|
||||
s().m_futureCbs.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::make_pair(time, id)),
|
||||
s().m_futureCbs.emplace(std::piecewise_construct, std::forward_as_tuple(time, id),
|
||||
std::forward_as_tuple(id, cb_data_p, nullptr));
|
||||
}
|
||||
static void cbNextAdd(uint64_t id, const s_cb_data* cb_data_p, QData time) {
|
||||
@@ -545,8 +550,7 @@ public:
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb reason=%d(NEXT) id=%" PRId64
|
||||
" time=%" PRIu64 " obj=%p\n",
|
||||
cb_data_p->reason, id, time, cb_data_p->obj););
|
||||
s().m_nextCbs.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::make_pair(time, id)),
|
||||
s().m_nextCbs.emplace(std::piecewise_construct, std::forward_as_tuple(time, id),
|
||||
std::forward_as_tuple(id, cb_data_p, nullptr));
|
||||
}
|
||||
static void cbReasonRemove(uint64_t id, uint32_t reason, QData time) {
|
||||
@@ -985,9 +989,117 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_PURE {
|
||||
"vpiGenVar",
|
||||
"vpiAutomatics"
|
||||
};
|
||||
static const char* const sv_names1[] = {
|
||||
"vpiPackage",
|
||||
"vpiInterface",
|
||||
"vpiProgram",
|
||||
"vpiInterfaceArray",
|
||||
"vpiProgramArray",
|
||||
"vpiTypespec",
|
||||
"vpiModport",
|
||||
"vpiInterfaceTfDecl",
|
||||
"vpiRefObj",
|
||||
"vpiTypeParameter",
|
||||
"vpiLongIntVar",
|
||||
"vpiShortIntVar",
|
||||
"vpiIntVar",
|
||||
"vpiShortRealVar",
|
||||
"vpiByteVar",
|
||||
"vpiClassVar",
|
||||
"vpiStringVar",
|
||||
"vpiEnumVar",
|
||||
"vpiStructVar",
|
||||
"vpiUnionVar",
|
||||
"vpiBitVar",
|
||||
"vpiClassObj",
|
||||
"vpiChandleVar",
|
||||
"vpiPackedArrayVar",
|
||||
"*undefined*", // 624 is not defined for object types
|
||||
"vpiLongIntTypespec",
|
||||
"vpiShortRealTypespec",
|
||||
"vpiByteTypespec",
|
||||
"vpiShortIntTypespec",
|
||||
"vpiIntTypespec",
|
||||
"vpiClassTypespec",
|
||||
"vpiStringTypespec",
|
||||
"vpiChandleTypespec",
|
||||
"vpiEnumTypespec",
|
||||
"vpiEnumConst",
|
||||
"vpiIntegerTypespec",
|
||||
"vpiTimeTypespec",
|
||||
"vpiRealTypespec",
|
||||
"vpiStructTypespec",
|
||||
"vpiUnionTypespec",
|
||||
"vpiBitTypespec",
|
||||
"vpiLogicTypespec",
|
||||
"vpiArrayTypespec",
|
||||
"vpiVoidTypespec",
|
||||
"vpiTypespecMember",
|
||||
"vpiDistItem",
|
||||
"vpiAliasStmt",
|
||||
"vpiThread",
|
||||
"vpiMethodFuncCall",
|
||||
"vpiMethodTaskCall",
|
||||
"vpiClockingBlock",
|
||||
"vpiClockingIODecl",
|
||||
"vpiClassDefn",
|
||||
"vpiConstraint",
|
||||
"vpiConstraintOrdering",
|
||||
"vpiPropertyDecl",
|
||||
"vpiPropertySpec",
|
||||
"vpiPropertyExpr",
|
||||
"vpiMulticlockSequenceExpr",
|
||||
"vpiClockedSeq",
|
||||
"vpiPropertyInst",
|
||||
"vpiSequenceDecl",
|
||||
"vpiCaseProperty",
|
||||
"*undefined*", // 663 is not defined for object types
|
||||
"vpiSequenceInst",
|
||||
"vpiImmediateAssert",
|
||||
"vpiReturn",
|
||||
"vpiAnyPattern",
|
||||
"vpiTaggedPattern",
|
||||
"vpiStructPattern",
|
||||
"vpiDoWhile",
|
||||
"vpiOrderedWait",
|
||||
"vpiWaitFork",
|
||||
"vpiDisableFork",
|
||||
"vpiExpectStmt",
|
||||
"vpiForeachStmt",
|
||||
"vpiFinal",
|
||||
"vpiExtends",
|
||||
"vpiDistribution",
|
||||
"vpiSeqFormalDecl",
|
||||
"vpiEnumNet",
|
||||
"vpiIntegerNet",
|
||||
"vpiTimeNet",
|
||||
"vpiStructNet",
|
||||
"vpiBreak",
|
||||
"vpiContinue",
|
||||
"vpiAssert",
|
||||
"vpiAssume",
|
||||
"vpiCover",
|
||||
"vpiDisableCondition",
|
||||
"vpiClockingEvent",
|
||||
"vpiReturnStmt",
|
||||
"vpiPackedArrayTypespec",
|
||||
"vpiPackedArrayNet",
|
||||
"vpiImmediateAssume",
|
||||
"vpiImmediateCover",
|
||||
"vpiSequenceTypespec",
|
||||
"vpiPropertyTypespec",
|
||||
"vpiEventTypespec",
|
||||
"vpiPropFormalDecl",
|
||||
};
|
||||
// clang-format on
|
||||
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
||||
return names[(vpiVal <= vpiAutomatics) ? vpiVal : 0];
|
||||
if (VL_UNCOVERABLE(vpiVal < 0))
|
||||
return names[0];
|
||||
else if (vpiVal <= vpiAutomatics)
|
||||
return names[vpiVal];
|
||||
else if (vpiVal >= vpiPackage && vpiVal <= vpiPropFormalDecl)
|
||||
return sv_names1[(vpiVal - vpiPackage)];
|
||||
else
|
||||
return names[0];
|
||||
}
|
||||
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_PURE {
|
||||
// clang-format off
|
||||
@@ -1313,6 +1425,104 @@ void VerilatedVpiError::selfTest() VL_MT_UNSAFE_ONE {
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiGenScope);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiGenVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAutomatics);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPackage);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiInterface);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiProgram);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiInterfaceArray);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiProgramArray);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiModport);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiInterfaceTfDecl);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiRefObj);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTypeParameter);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiLongIntVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiShortIntVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiIntVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiShortRealVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiByteVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStringVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBitVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassObj);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiChandleVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPackedArrayVar);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiLongIntTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiShortRealTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiByteTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiShortIntTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiIntTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStringTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiChandleTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumConst);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiIntegerTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTimeTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiRealTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUnionTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBitTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiLogicTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiArrayTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiVoidTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTypespecMember);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDistItem);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAliasStmt);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiThread);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiMethodFuncCall);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiMethodTaskCall);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClockingBlock);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClockingIODecl);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClassDefn);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiConstraint);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiConstraintOrdering);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertyDecl);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertySpec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertyExpr);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiMulticlockSequenceExpr);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClockedSeq);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertyInst);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiSequenceDecl);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiCaseProperty);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiSequenceInst);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiImmediateAssert);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiReturn);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAnyPattern);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTaggedPattern);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructPattern);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDoWhile);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiOrderedWait);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiWaitFork);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDisableFork);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiExpectStmt);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiForeachStmt);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiFinal);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiExtends);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDistribution);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiSeqFormalDecl);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEnumNet);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiIntegerNet);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiTimeNet);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiStructNet);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiBreak);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiContinue);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAssert);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAssume);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiCover);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiDisableCondition);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiClockingEvent);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiReturnStmt);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPackedArrayTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPackedArrayNet);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiImmediateAssume);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiImmediateCover);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiSequenceTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropertyTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiEventTypespec);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiPropFormalDecl);
|
||||
|
||||
SELF_CHECK_ENUM_STR(strFromVpiMethod, vpiCondition);
|
||||
SELF_CHECK_ENUM_STR(strFromVpiMethod, vpiStmt);
|
||||
@@ -1734,7 +1944,8 @@ bool vl_check_format(const VerilatedVar* varp, const p_vpi_value valuep, const c
|
||||
case VLVT_UINT64:
|
||||
case VLVT_WDATA: return status;
|
||||
case VLVT_STRING:
|
||||
if (isGetValue) {
|
||||
// string parameter values can't be changed
|
||||
if (isGetValue || !varp->isParam()) {
|
||||
return status;
|
||||
} else {
|
||||
status = false;
|
||||
@@ -1749,6 +1960,11 @@ bool vl_check_format(const VerilatedVar* varp, const p_vpi_value valuep, const c
|
||||
case VLVT_UINT32: return status;
|
||||
default: status = false;
|
||||
}
|
||||
} else if (valuep->format == vpiRealVal) {
|
||||
switch (varp->vltype()) {
|
||||
case VLVT_REAL: return status;
|
||||
default: status = false;
|
||||
}
|
||||
} else if (valuep->format == vpiSuppressVal) {
|
||||
return status;
|
||||
} else {
|
||||
@@ -1766,6 +1982,8 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
static thread_local char t_outStr[VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE + 1];
|
||||
// cppcheck-suppress variableScope
|
||||
static const thread_local int t_outStrSz = sizeof(t_outStr) - 1;
|
||||
// string data type is dynamic and may vary in size during simulation
|
||||
static thread_local std::string t_outDynamicStr;
|
||||
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
||||
// This may cause backward compatibility issues with older code.
|
||||
if (valuep->format == vpiVectorVal) {
|
||||
@@ -1918,8 +2136,14 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
return;
|
||||
} else if (valuep->format == vpiStringVal) {
|
||||
if (varp->vltype() == VLVT_STRING) {
|
||||
valuep->value.str = reinterpret_cast<char*>(varDatap);
|
||||
return;
|
||||
if (varp->isParam()) {
|
||||
valuep->value.str = reinterpret_cast<char*>(varDatap);
|
||||
return;
|
||||
} else {
|
||||
t_outDynamicStr = *(reinterpret_cast<std::string*>(varDatap));
|
||||
valuep->value.str = const_cast<char*>(t_outDynamicStr.c_str());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
valuep->value.str = t_outStr;
|
||||
int bytes = VL_BYTES_I(varp->packed().elements());
|
||||
@@ -1954,6 +2178,9 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
valuep->value.integer = *(reinterpret_cast<IData*>(varDatap));
|
||||
return;
|
||||
}
|
||||
} else if (valuep->format == vpiRealVal) {
|
||||
valuep->value.real = *(reinterpret_cast<double*>(varDatap));
|
||||
return;
|
||||
} else if (valuep->format == vpiSuppressVal) {
|
||||
return;
|
||||
}
|
||||
@@ -2171,12 +2398,17 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
||||
datap[(chars - 1) >> 1] &= vop->mask_byte((chars - 1) >> 1);
|
||||
return object;
|
||||
} else if (valuep->format == vpiStringVal) {
|
||||
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
|
||||
const int len = std::strlen(valuep->value.str);
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
for (int i = 0; i < bytes; ++i) {
|
||||
// prepend with 0 values before placing string the least significant bytes
|
||||
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
|
||||
if (vop->varp()->vltype() == VLVT_STRING) {
|
||||
*(reinterpret_cast<std::string*>(vop->varDatap())) = valuep->value.str;
|
||||
return object;
|
||||
} else {
|
||||
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
|
||||
const int len = std::strlen(valuep->value.str);
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
for (int i = 0; i < bytes; ++i) {
|
||||
// prepend with 0 values before placing string the least significant bytes
|
||||
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
|
||||
}
|
||||
}
|
||||
return object;
|
||||
} else if (valuep->format == vpiIntVal) {
|
||||
@@ -2190,6 +2422,11 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
||||
*(reinterpret_cast<IData*>(vop->varDatap())) = vop->mask() & valuep->value.integer;
|
||||
return object;
|
||||
}
|
||||
} else if (valuep->format == vpiRealVal) {
|
||||
if (vop->varp()->vltype() == VLVT_REAL) {
|
||||
*(reinterpret_cast<double*>(vop->varDatap())) = valuep->value.real;
|
||||
return object;
|
||||
}
|
||||
}
|
||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s",
|
||||
__func__, VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
#include "verilated_syms.h"
|
||||
|
||||
//======================================================================
|
||||
// From IEEE 1800-2009 annex K
|
||||
// From IEEE 1800-2017 annex M
|
||||
|
||||
#include "vltstd/vpi_user.h"
|
||||
#include "vltstd/sv_vpi_user.h"
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
||||
@@ -0,0 +1,570 @@
|
||||
/***************************************************************************
|
||||
* sv_vpi_user.h
|
||||
*
|
||||
* SystemVerilog VPI extensions.
|
||||
*
|
||||
* This file contains the constant definitions, structure definitions, and
|
||||
* routine declarations used by the SystemVerilog Verification Procedural
|
||||
* Interface (VPI) access routines.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* NOTE:
|
||||
* The constant values 600 through 999 are reserved for use in this file.
|
||||
* - the range 600-749 is reserved for SV VPI model extensions
|
||||
* - the range 750-779 is reserved for the Coverage VPI
|
||||
* - the range 800-899 is reserved for future use
|
||||
* Overlaps in the numerical ranges are permitted for different categories
|
||||
* of identifiers; e.g.
|
||||
* - object types
|
||||
* - properties
|
||||
* - callbacks
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SV_VPI_USER_H
|
||||
#define SV_VPI_USER_H
|
||||
|
||||
#include "vpi_user.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/****************************** OBJECT TYPES ******************************/
|
||||
#define vpiPackage 600
|
||||
#define vpiInterface 601
|
||||
#define vpiProgram 602
|
||||
#define vpiInterfaceArray 603
|
||||
#define vpiProgramArray 604
|
||||
#define vpiTypespec 605
|
||||
#define vpiModport 606
|
||||
#define vpiInterfaceTfDecl 607
|
||||
#define vpiRefObj 608
|
||||
#define vpiTypeParameter 609
|
||||
|
||||
/* variables */
|
||||
#define vpiVarBit vpiRegBit
|
||||
#define vpiLongIntVar 610
|
||||
#define vpiShortIntVar 611
|
||||
#define vpiIntVar 612
|
||||
#define vpiShortRealVar 613
|
||||
#define vpiByteVar 614
|
||||
#define vpiClassVar 615
|
||||
#define vpiStringVar 616
|
||||
#define vpiEnumVar 617
|
||||
#define vpiStructVar 618
|
||||
#define vpiUnionVar 619
|
||||
#define vpiBitVar 620
|
||||
#define vpiLogicVar vpiReg
|
||||
#define vpiArrayVar vpiRegArray
|
||||
#define vpiClassObj 621
|
||||
#define vpiChandleVar 622
|
||||
#define vpiPackedArrayVar 623
|
||||
#define vpiVirtualInterfaceVar 728
|
||||
|
||||
/* typespecs */
|
||||
#define vpiLongIntTypespec 625
|
||||
#define vpiShortRealTypespec 626
|
||||
#define vpiByteTypespec 627
|
||||
#define vpiShortIntTypespec 628
|
||||
#define vpiIntTypespec 629
|
||||
#define vpiClassTypespec 630
|
||||
#define vpiStringTypespec 631
|
||||
#define vpiChandleTypespec 632
|
||||
#define vpiEnumTypespec 633
|
||||
#define vpiEnumConst 634
|
||||
#define vpiIntegerTypespec 635
|
||||
#define vpiTimeTypespec 636
|
||||
#define vpiRealTypespec 637
|
||||
#define vpiStructTypespec 638
|
||||
#define vpiUnionTypespec 639
|
||||
#define vpiBitTypespec 640
|
||||
#define vpiLogicTypespec 641
|
||||
#define vpiArrayTypespec 642
|
||||
#define vpiVoidTypespec 643
|
||||
#define vpiTypespecMember 644
|
||||
#define vpiPackedArrayTypespec 692
|
||||
#define vpiSequenceTypespec 696
|
||||
#define vpiPropertyTypespec 697
|
||||
#define vpiEventTypespec 698
|
||||
#define vpiInterfaceTypespec 906
|
||||
|
||||
#define vpiClockingBlock 650
|
||||
#define vpiClockingIODecl 651
|
||||
#define vpiClassDefn 652
|
||||
#define vpiConstraint 653
|
||||
#define vpiConstraintOrdering 654
|
||||
|
||||
#define vpiDistItem 645
|
||||
#define vpiAliasStmt 646
|
||||
#define vpiThread 647
|
||||
#define vpiMethodFuncCall 648
|
||||
#define vpiMethodTaskCall 649
|
||||
|
||||
/* concurrent assertions */
|
||||
#define vpiAssert 686
|
||||
#define vpiAssume 687
|
||||
#define vpiCover 688
|
||||
#define vpiRestrict 901
|
||||
|
||||
#define vpiDisableCondition 689
|
||||
#define vpiClockingEvent 690
|
||||
/* property decl, spec */
|
||||
#define vpiPropertyDecl 655
|
||||
#define vpiPropertySpec 656
|
||||
#define vpiPropertyExpr 657
|
||||
#define vpiMulticlockSequenceExpr 658
|
||||
#define vpiClockedSeq 659
|
||||
#define vpiClockedProp 902
|
||||
#define vpiPropertyInst 660
|
||||
#define vpiSequenceDecl 661
|
||||
#define vpiCaseProperty 662 /* property case */
|
||||
#define vpiCasePropertyItem 905 /* property case item */
|
||||
#define vpiSequenceInst 664
|
||||
#define vpiImmediateAssert 665
|
||||
#define vpiImmediateAssume 694
|
||||
#define vpiImmediateCover 695
|
||||
#define vpiReturn 666
|
||||
/* pattern */
|
||||
#define vpiAnyPattern 667
|
||||
#define vpiTaggedPattern 668
|
||||
#define vpiStructPattern 669
|
||||
/* do .. while */
|
||||
#define vpiDoWhile 670
|
||||
/* waits */
|
||||
#define vpiOrderedWait 671
|
||||
#define vpiWaitFork 672
|
||||
/* disables */
|
||||
#define vpiDisableFork 673
|
||||
#define vpiExpectStmt 674
|
||||
#define vpiForeachStmt 675
|
||||
#define vpiReturnStmt 691
|
||||
#define vpiFinal 676
|
||||
#define vpiExtends 677
|
||||
#define vpiDistribution 678
|
||||
#define vpiSeqFormalDecl 679
|
||||
#define vpiPropFormalDecl 699
|
||||
#define vpiArrayNet vpiNetArray
|
||||
#define vpiEnumNet 680
|
||||
#define vpiIntegerNet 681
|
||||
#define vpiLogicNet vpiNet
|
||||
#define vpiTimeNet 682
|
||||
#define vpiStructNet 683
|
||||
#define vpiBreak 684
|
||||
#define vpiContinue 685
|
||||
#define vpiPackedArrayNet 693
|
||||
#define vpiConstraintExpr 747
|
||||
#define vpiElseConst 748
|
||||
#define vpiImplication 749
|
||||
#define vpiConstrIf 738
|
||||
#define vpiConstrIfElse 739
|
||||
#define vpiConstrForEach 736
|
||||
#define vpiSoftDisable 733
|
||||
#define vpiLetDecl 903
|
||||
#define vpiLetExpr 904
|
||||
|
||||
/******************************** METHODS *********************************/
|
||||
/************* methods used to traverse 1 to 1 relationships **************/
|
||||
#define vpiActual 700
|
||||
|
||||
#define vpiTypedefAlias 701
|
||||
|
||||
#define vpiIndexTypespec 702
|
||||
#define vpiBaseTypespec 703
|
||||
#define vpiElemTypespec 704
|
||||
|
||||
#define vpiInputSkew 706
|
||||
#define vpiOutputSkew 707
|
||||
#define vpiGlobalClocking 708
|
||||
#define vpiDefaultClocking 709
|
||||
#define vpiDefaultDisableIff 710
|
||||
|
||||
#define vpiOrigin 713
|
||||
#define vpiPrefix 714
|
||||
#define vpiWith 715
|
||||
|
||||
#define vpiProperty 718
|
||||
|
||||
#define vpiValueRange 720
|
||||
#define vpiPattern 721
|
||||
#define vpiWeight 722
|
||||
#define vpiConstraintItem 746
|
||||
|
||||
/************ methods used to traverse 1 to many relationships ************/
|
||||
#define vpiTypedef 725
|
||||
#define vpiImport 726
|
||||
#define vpiDerivedClasses 727
|
||||
#define vpiInterfaceDecl vpiVirtualInterfaceVar /* interface decl deprecated */
|
||||
|
||||
#define vpiMethods 730
|
||||
#define vpiSolveBefore 731
|
||||
#define vpiSolveAfter 732
|
||||
|
||||
#define vpiWaitingProcesses 734
|
||||
|
||||
#define vpiMessages 735
|
||||
#define vpiLoopVars 737
|
||||
|
||||
#define vpiConcurrentAssertions 740
|
||||
#define vpiMatchItem 741
|
||||
#define vpiMember 742
|
||||
#define vpiElement 743
|
||||
|
||||
/************* methods used to traverse 1 to many relationships ***************/
|
||||
#define vpiAssertion 744
|
||||
|
||||
/*********** methods used to traverse both 1-1 and 1-many relations ***********/
|
||||
#define vpiInstance 745
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/************************ generic object properties ***********************/
|
||||
/**************************************************************************/
|
||||
#define vpiTop 600
|
||||
|
||||
#define vpiUnit 602
|
||||
|
||||
#define vpiJoinType 603
|
||||
#define vpiJoin 0
|
||||
#define vpiJoinNone 1
|
||||
#define vpiJoinAny 2
|
||||
|
||||
#define vpiAccessType 604
|
||||
#define vpiForkJoinAcc 1
|
||||
#define vpiExternAcc 2
|
||||
#define vpiDPIExportAcc 3
|
||||
#define vpiDPIImportAcc 4
|
||||
|
||||
#define vpiArrayType 606
|
||||
#define vpiStaticArray 1
|
||||
#define vpiDynamicArray 2
|
||||
#define vpiAssocArray 3
|
||||
#define vpiQueueArray 4
|
||||
#define vpiArrayMember 607
|
||||
|
||||
#define vpiIsRandomized 608
|
||||
#define vpiLocalVarDecls 609
|
||||
#define vpiOpStrong 656 /* strength of temporal operator */
|
||||
#define vpiRandType 610
|
||||
#define vpiNotRand 1
|
||||
#define vpiRand 2
|
||||
#define vpiRandC 3
|
||||
#define vpiPortType 611
|
||||
#define vpiInterfacePort 1
|
||||
#define vpiModportPort 2
|
||||
/* vpiPort is also a port type. It is defined in vpi_user.h */
|
||||
|
||||
|
||||
#define vpiConstantVariable 612
|
||||
#define vpiStructUnionMember 615
|
||||
|
||||
#define vpiVisibility 620
|
||||
#define vpiPublicVis 1
|
||||
#define vpiProtectedVis 2
|
||||
#define vpiLocalVis 3
|
||||
|
||||
/* Return values for vpiConstType property */
|
||||
#define vpiOneStepConst 9
|
||||
#define vpiUnboundedConst 10
|
||||
#define vpiNullConst 11
|
||||
|
||||
#define vpiAlwaysType 624
|
||||
#define vpiAlwaysComb 2
|
||||
#define vpiAlwaysFF 3
|
||||
#define vpiAlwaysLatch 4
|
||||
|
||||
#define vpiDistType 625
|
||||
#define vpiEqualDist 1 /* constraint equal distribution */
|
||||
#define vpiDivDist 2 /* constraint divided distribution */
|
||||
|
||||
#define vpiPacked 630
|
||||
#define vpiTagged 632
|
||||
#define vpiRef 6 /* Return value for vpiDirection property */
|
||||
#define vpiVirtual 635
|
||||
#define vpiHasActual 636
|
||||
#define vpiIsConstraintEnabled 638
|
||||
#define vpiSoft 639
|
||||
|
||||
|
||||
#define vpiClassType 640
|
||||
#define vpiMailboxClass 1
|
||||
#define vpiSemaphoreClass 2
|
||||
#define vpiUserDefinedClass 3
|
||||
#define vpiProcessClass 4
|
||||
|
||||
#define vpiMethod 645
|
||||
#define vpiIsClockInferred 649
|
||||
#define vpiIsDeferred 657
|
||||
#define vpiIsFinal 670
|
||||
#define vpiIsCoverSequence 659
|
||||
#define vpiQualifier 650
|
||||
#define vpiNoQualifier 0
|
||||
#define vpiUniqueQualifier 1
|
||||
#define vpiPriorityQualifier 2
|
||||
#define vpiTaggedQualifier 4
|
||||
#define vpiRandQualifier 8
|
||||
#define vpiInsideQualifier 16
|
||||
|
||||
#define vpiInputEdge 651 /* returns vpiNoEdge, vpiPosedge,
|
||||
vpiNegedge */
|
||||
#define vpiOutputEdge 652 /* returns vpiNoEdge, vpiPosedge,
|
||||
vpiNegedge */
|
||||
#define vpiGeneric 653
|
||||
|
||||
/* Compatibility-mode property and values (object argument == NULL) */
|
||||
#define vpiCompatibilityMode 654
|
||||
#define vpiMode1364v1995 1
|
||||
#define vpiMode1364v2001 2
|
||||
#define vpiMode1364v2005 3
|
||||
#define vpiMode1800v2005 4
|
||||
#define vpiMode1800v2009 5
|
||||
|
||||
#define vpiPackedArrayMember 655
|
||||
#define vpiStartLine 661
|
||||
#define vpiColumn 662
|
||||
#define vpiEndLine 663
|
||||
#define vpiEndColumn 664
|
||||
|
||||
/* memory allocation scheme for transient objects */
|
||||
#define vpiAllocScheme 658
|
||||
#define vpiAutomaticScheme 1
|
||||
#define vpiDynamicScheme 2
|
||||
#define vpiOtherScheme 3
|
||||
|
||||
#define vpiObjId 660
|
||||
|
||||
#define vpiDPIPure 665
|
||||
#define vpiDPIContext 666
|
||||
#define vpiDPICStr 667
|
||||
#define vpiDPI 1
|
||||
#define vpiDPIC 2
|
||||
#define vpiDPICIdentifier 668
|
||||
#define vpiIsModPort 669
|
||||
|
||||
/******************************** Operators *******************************/
|
||||
#define vpiImplyOp 50 /* -> implication operator */
|
||||
#define vpiNonOverlapImplyOp 51 /* |=> nonoverlapped implication */
|
||||
#define vpiOverlapImplyOp 52 /* |-> overlapped implication operator */
|
||||
#define vpiAcceptOnOp 83 /* accept_on operator */
|
||||
#define vpiRejectOnOp 84 /* reject_on operator */
|
||||
#define vpiSyncAcceptOnOp 85 /* sync_accept_on operator */
|
||||
#define vpiSyncRejectOnOp 86 /* sync_reject_on operator */
|
||||
#define vpiOverlapFollowedByOp 87 /* overlapped followed_by operator */
|
||||
#define vpiNonOverlapFollowedByOp 88 /* nonoverlapped followed_by operator */
|
||||
#define vpiNexttimeOp 89 /* nexttime operator */
|
||||
#define vpiAlwaysOp 90 /* always operator */
|
||||
#define vpiEventuallyOp 91 /* eventually operator */
|
||||
#define vpiUntilOp 92 /* until operator */
|
||||
#define vpiUntilWithOp 93 /* until_with operator */
|
||||
|
||||
#define vpiUnaryCycleDelayOp 53 /* binary cycle delay (##) operator */
|
||||
#define vpiCycleDelayOp 54 /* binary cycle delay (##) operator */
|
||||
#define vpiIntersectOp 55 /* intersection operator */
|
||||
#define vpiFirstMatchOp 56 /* first_match operator */
|
||||
#define vpiThroughoutOp 57 /* throughout operator */
|
||||
#define vpiWithinOp 58 /* within operator */
|
||||
#define vpiRepeatOp 59 /* [=] nonconsecutive repetition */
|
||||
#define vpiConsecutiveRepeatOp 60 /* [*] consecutive repetition */
|
||||
#define vpiGotoRepeatOp 61 /* [->] goto repetition */
|
||||
|
||||
#define vpiPostIncOp 62 /* ++ post-increment */
|
||||
#define vpiPreIncOp 63 /* ++ pre-increment */
|
||||
#define vpiPostDecOp 64 /* -- post-decrement */
|
||||
#define vpiPreDecOp 65 /* -- pre-decrement */
|
||||
|
||||
#define vpiMatchOp 66 /* match() operator */
|
||||
#define vpiCastOp 67 /* type'() operator */
|
||||
#define vpiIffOp 68 /* iff operator */
|
||||
#define vpiWildEqOp 69 /* ==? operator */
|
||||
#define vpiWildNeqOp 70 /* !=? operator */
|
||||
|
||||
#define vpiStreamLROp 71 /* left-to-right streaming {>>} operator */
|
||||
#define vpiStreamRLOp 72 /* right-to-left streaming {<<} operator */
|
||||
|
||||
#define vpiMatchedOp 73 /* the .matched sequence operation */
|
||||
#define vpiTriggeredOp 74 /* the .triggered sequence operation */
|
||||
#define vpiAssignmentPatternOp 75 /* '{} assignment pattern */
|
||||
#define vpiMultiAssignmentPatternOp 76 /* '{n{}} multi assignment pattern */
|
||||
#define vpiIfOp 77 /* if operator */
|
||||
#define vpiIfElseOp 78 /* if-else operator */
|
||||
#define vpiCompAndOp 79 /* Composite and operator */
|
||||
#define vpiCompOrOp 80 /* Composite or operator */
|
||||
#define vpiImpliesOp 94 /* implies operator */
|
||||
#define vpiInsideOp 95 /* inside operator */
|
||||
#define vpiTypeOp 81 /* type operator */
|
||||
#define vpiAssignmentOp 82 /* Normal assignment */
|
||||
|
||||
/*********************** task/function properties ***********************/
|
||||
#define vpiOtherFunc 6 /* returns other types; for property vpiFuncType */
|
||||
|
||||
/* vpiValid and vpiValidUnknown were deprecated in 1800-2009 */
|
||||
/*********************** value for vpiValid *****************************/
|
||||
#define vpiValidUnknown 2 /* Validity of variable is unknown */
|
||||
|
||||
/************************** STRUCTURE DEFINITIONS *************************/
|
||||
|
||||
/***************************** structure *****************************/
|
||||
|
||||
/**************************** CALLBACK REASONS ****************************/
|
||||
#define cbStartOfThread 600 /* callback on thread creation */
|
||||
#define cbEndOfThread 601 /* callback on thread termination */
|
||||
#define cbEnterThread 602 /* callback on reentering thread */
|
||||
#define cbStartOfFrame 603 /* callback on frame creation */
|
||||
#define cbEndOfFrame 604 /* callback on frame exit */
|
||||
#define cbSizeChange 605 /* callback on array variable size change */
|
||||
#define cbCreateObj 700 /* callback on class object creation */
|
||||
#define cbReclaimObj 701 /* callback on class object reclaimed by
|
||||
automatic memory management */
|
||||
#define cbEndOfObject 702 /* callback on transient object deletion */
|
||||
|
||||
/************************* FUNCTION DECLARATIONS **************************/
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*************************** Coverage VPI *********************************/
|
||||
/**************************************************************************/
|
||||
|
||||
/* coverage control */
|
||||
#define vpiCoverageStart 750
|
||||
#define vpiCoverageStop 751
|
||||
#define vpiCoverageReset 752
|
||||
#define vpiCoverageCheck 753
|
||||
#define vpiCoverageMerge 754
|
||||
#define vpiCoverageSave 755
|
||||
|
||||
/* coverage type properties */
|
||||
#define vpiAssertCoverage 760
|
||||
#define vpiFsmStateCoverage 761
|
||||
#define vpiStatementCoverage 762
|
||||
#define vpiToggleCoverage 763
|
||||
|
||||
/* coverage status properties */
|
||||
#define vpiCovered 765
|
||||
#define vpiCoverMax 766 /* preserved for backward compatibility */
|
||||
#define vpiCoveredMax 766
|
||||
#define vpiCoveredCount 767
|
||||
|
||||
/* assertion-specific coverage status properties */
|
||||
#define vpiAssertAttemptCovered 770
|
||||
#define vpiAssertSuccessCovered 771
|
||||
#define vpiAssertFailureCovered 772
|
||||
#define vpiAssertVacuousSuccessCovered 773
|
||||
#define vpiAssertDisableCovered 774
|
||||
#define vpiAssertKillCovered 777
|
||||
|
||||
/* FSM-specific coverage status properties */
|
||||
#define vpiFsmStates 775
|
||||
#define vpiFsmStateExpression 776
|
||||
|
||||
/* FSM handle types */
|
||||
#define vpiFsm 758
|
||||
#define vpiFsmHandle 759
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/***************************** Assertion VPI *******************************/
|
||||
/***************************************************************************/
|
||||
|
||||
/* assertion callback types */
|
||||
#define cbAssertionStart 606
|
||||
#define cbAssertionSuccess 607
|
||||
#define cbAssertionFailure 608
|
||||
#define cbAssertionVacuousSuccess 657
|
||||
#define cbAssertionDisabledEvaluation 658
|
||||
#define cbAssertionStepSuccess 609
|
||||
#define cbAssertionStepFailure 610
|
||||
#define cbAssertionLock 661
|
||||
#define cbAssertionUnlock 662
|
||||
#define cbAssertionDisable 611
|
||||
#define cbAssertionEnable 612
|
||||
#define cbAssertionReset 613
|
||||
#define cbAssertionKill 614
|
||||
#define cbAssertionEnablePassAction 645
|
||||
#define cbAssertionEnableFailAction 646
|
||||
#define cbAssertionDisablePassAction 647
|
||||
#define cbAssertionDisableFailAction 648
|
||||
#define cbAssertionEnableNonvacuousAction 649
|
||||
#define cbAssertionDisableVacuousAction 650
|
||||
|
||||
/* assertion "system" callback types */
|
||||
#define cbAssertionSysInitialized 615
|
||||
#define cbAssertionSysOn 616
|
||||
#define cbAssertionSysOff 617
|
||||
#define cbAssertionSysKill 631
|
||||
#define cbAssertionSysLock 659
|
||||
#define cbAssertionSysUnlock 660
|
||||
#define cbAssertionSysEnd 618
|
||||
#define cbAssertionSysReset 619
|
||||
#define cbAssertionSysEnablePassAction 651
|
||||
#define cbAssertionSysEnableFailAction 652
|
||||
#define cbAssertionSysDisablePassAction 653
|
||||
#define cbAssertionSysDisableFailAction 654
|
||||
#define cbAssertionSysEnableNonvacuousAction 655
|
||||
#define cbAssertionSysDisableVacuousAction 656
|
||||
|
||||
/* assertion control constants */
|
||||
#define vpiAssertionLock 645
|
||||
#define vpiAssertionUnlock 646
|
||||
#define vpiAssertionDisable 620
|
||||
#define vpiAssertionEnable 621
|
||||
#define vpiAssertionReset 622
|
||||
#define vpiAssertionKill 623
|
||||
#define vpiAssertionEnableStep 624
|
||||
#define vpiAssertionDisableStep 625
|
||||
#define vpiAssertionClockSteps 626
|
||||
#define vpiAssertionSysLock 647
|
||||
#define vpiAssertionSysUnlock 648
|
||||
#define vpiAssertionSysOn 627
|
||||
#define vpiAssertionSysOff 628
|
||||
#define vpiAssertionSysKill 632
|
||||
#define vpiAssertionSysEnd 629
|
||||
#define vpiAssertionSysReset 630
|
||||
#define vpiAssertionDisablePassAction 633
|
||||
#define vpiAssertionEnablePassAction 634
|
||||
#define vpiAssertionDisableFailAction 635
|
||||
#define vpiAssertionEnableFailAction 636
|
||||
#define vpiAssertionDisableVacuousAction 637
|
||||
#define vpiAssertionEnableNonvacuousAction 638
|
||||
#define vpiAssertionSysEnablePassAction 639
|
||||
#define vpiAssertionSysEnableFailAction 640
|
||||
#define vpiAssertionSysDisablePassAction 641
|
||||
#define vpiAssertionSysDisableFailAction 642
|
||||
#define vpiAssertionSysEnableNonvacuousAction 643
|
||||
#define vpiAssertionSysDisableVacuousAction 644
|
||||
|
||||
typedef struct t_vpi_assertion_step_info {
|
||||
PLI_INT32 matched_expression_count;
|
||||
vpiHandle *matched_exprs; /* array of expressions */
|
||||
PLI_INT32 stateFrom, stateTo; /* identify transition */
|
||||
} s_vpi_assertion_step_info, *p_vpi_assertion_step_info;
|
||||
|
||||
typedef struct t_vpi_attempt_info {
|
||||
union {
|
||||
vpiHandle failExpr;
|
||||
p_vpi_assertion_step_info step;
|
||||
} detail;
|
||||
s_vpi_time attemptStartTime; /* Time attempt triggered */
|
||||
} s_vpi_attempt_info, *p_vpi_attempt_info;
|
||||
|
||||
/* typedef for vpi_register_assertion_cb callback function */
|
||||
typedef PLI_INT32(vpi_assertion_callback_func)(
|
||||
PLI_INT32 reason, /* callback reason */
|
||||
p_vpi_time cb_time, /* callback time */
|
||||
vpiHandle assertion, /* handle to assertion */
|
||||
p_vpi_attempt_info info, /* attempt related information */
|
||||
PLI_BYTE8 *user_data /* user data entered upon registration */
|
||||
);
|
||||
|
||||
vpiHandle vpi_register_assertion_cb(
|
||||
vpiHandle assertion, /* handle to assertion */
|
||||
PLI_INT32 reason, /* reason for which callbacks needed */
|
||||
vpi_assertion_callback_func *cb_rtn,
|
||||
PLI_BYTE8 *user_data /* user data to be supplied to cb */
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -955,6 +955,7 @@ def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
||||
compile_command.directory)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ParallelAnalysisProcess:
|
||||
cav: Optional[CallAnnotationsValidator] = None
|
||||
diags: set[Diagnostic] = dataclasses.field(default_factory=set)
|
||||
|
||||
@@ -316,7 +316,7 @@ def run(command):
|
||||
print("\t%s" % command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status < 0:
|
||||
raise Exception("%Error: Command failed " + command + ", stopped")
|
||||
raise RuntimeError("%Error: Command failed " + command + ", stopped")
|
||||
|
||||
|
||||
def unlink_ok(filename):
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ def run(command):
|
||||
os.system(command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status < 0:
|
||||
raise Exception("%Error: Command failed " + command + ", stopped")
|
||||
raise RuntimeError("%Error: Command failed " + command + ", stopped")
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
+16
-6
@@ -35,7 +35,6 @@ set(HEADERS
|
||||
V3Assert.h
|
||||
V3AssertPre.h
|
||||
V3Ast.h
|
||||
V3AstConstOnly.h
|
||||
V3AstInlines.h
|
||||
V3AstNodeDType.h
|
||||
V3AstNodeExpr.h
|
||||
@@ -44,9 +43,10 @@ set(HEADERS
|
||||
V3Begin.h
|
||||
V3Branch.h
|
||||
V3Broken.h
|
||||
V3CCtors.h
|
||||
V3CUse.h
|
||||
V3Case.h
|
||||
V3Cast.h
|
||||
V3CCtors.h
|
||||
V3Class.h
|
||||
V3Clean.h
|
||||
V3Clock.h
|
||||
@@ -56,7 +56,6 @@ set(HEADERS
|
||||
V3Const.h
|
||||
V3Coverage.h
|
||||
V3CoverageJoin.h
|
||||
V3CUse.h
|
||||
V3Dead.h
|
||||
V3Delayed.h
|
||||
V3Depth.h
|
||||
@@ -96,6 +95,7 @@ set(HEADERS
|
||||
V3Inline.h
|
||||
V3Inst.h
|
||||
V3InstrCount.h
|
||||
V3Interface.h
|
||||
V3LangCode.h
|
||||
V3LanguageWords.h
|
||||
V3Life.h
|
||||
@@ -104,13 +104,16 @@ set(HEADERS
|
||||
V3LinkDot.h
|
||||
V3LinkInc.h
|
||||
V3LinkJump.h
|
||||
V3LinkLevel.h
|
||||
V3LinkLValue.h
|
||||
V3LinkLevel.h
|
||||
V3LinkParse.h
|
||||
V3LinkResolve.h
|
||||
V3List.h
|
||||
V3Localize.h
|
||||
V3MemberMap.h
|
||||
V3MergeCond.h
|
||||
V3Mutex.h
|
||||
V3Name.h
|
||||
V3Name.h
|
||||
V3Number.h
|
||||
V3OptionParser.h
|
||||
@@ -126,13 +129,16 @@ set(HEADERS
|
||||
V3ParseSym.h
|
||||
V3Partition.h
|
||||
V3PartitionGraph.h
|
||||
V3PchAstMT.h
|
||||
V3PchAstNoMT.h
|
||||
V3PreLex.h
|
||||
V3Premit.h
|
||||
V3PreProc.h
|
||||
V3PreShell.h
|
||||
V3Premit.h
|
||||
V3ProtectLib.h
|
||||
V3Randomize.h
|
||||
V3Reloop.h
|
||||
V3Rtti.h
|
||||
V3Sched.h
|
||||
V3Scope.h
|
||||
V3Scoreboard.h
|
||||
@@ -148,6 +154,7 @@ set(HEADERS
|
||||
V3String.h
|
||||
V3Subst.h
|
||||
V3SymTable.h
|
||||
V3TSP.h
|
||||
V3Table.h
|
||||
V3Task.h
|
||||
V3ThreadPool.h
|
||||
@@ -156,7 +163,6 @@ set(HEADERS
|
||||
V3Trace.h
|
||||
V3TraceDecl.h
|
||||
V3Tristate.h
|
||||
V3TSP.h
|
||||
V3Undriven.h
|
||||
V3UniqueNames.h
|
||||
V3Unknown.h
|
||||
@@ -165,6 +171,7 @@ set(HEADERS
|
||||
V3Waiver.h
|
||||
V3Width.h
|
||||
V3WidthCommit.h
|
||||
V3WidthRemove.h
|
||||
VlcBucket.h
|
||||
VlcOptions.h
|
||||
VlcPoint.h
|
||||
@@ -220,6 +227,7 @@ set(COMMON_SOURCES
|
||||
V3EmitCMain.cpp
|
||||
V3EmitCMake.cpp
|
||||
V3EmitCModel.cpp
|
||||
V3EmitCPch.cpp
|
||||
V3EmitCSyms.cpp
|
||||
V3EmitMk.cpp
|
||||
V3EmitV.cpp
|
||||
@@ -243,6 +251,7 @@ set(COMMON_SOURCES
|
||||
V3Inline.cpp
|
||||
V3Inst.cpp
|
||||
V3InstrCount.cpp
|
||||
V3Interface.cpp
|
||||
V3Life.cpp
|
||||
V3LifePost.cpp
|
||||
V3LinkCells.cpp
|
||||
@@ -296,6 +305,7 @@ set(COMMON_SOURCES
|
||||
V3VariableOrder.cpp
|
||||
V3Waiver.cpp
|
||||
V3Width.cpp
|
||||
V3WidthCommit.cpp
|
||||
V3WidthSel.cpp
|
||||
V3ParseImp.cpp
|
||||
V3ParseGrammar.cpp
|
||||
|
||||
+84
-49
@@ -67,6 +67,11 @@ CFG_CXXFLAGS_PARSER = @CFG_CXXFLAGS_PARSER@
|
||||
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
|
||||
CFG_LDFLAGS_SRC = @CFG_LDFLAGS_SRC@
|
||||
CFG_LIBS = @CFG_LIBS@
|
||||
CFG_CXXFLAGS_PCH = -x c++-header
|
||||
# Compiler option to put in front of filename to read precompiled header
|
||||
CFG_CXXFLAGS_PCH_I = @CFG_CXXFLAGS_PCH_I@
|
||||
# Compiler's filename prefix for precompiled headers, .gch if clang, empty if GCC
|
||||
CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
@@ -129,6 +134,11 @@ BISONPRE = $(srcdir)/bisonpre
|
||||
FLEXFIX = $(srcdir)/flexfix
|
||||
VLCOVGEN = $(srcdir)/vlcovgen
|
||||
|
||||
######################################################################
|
||||
# CCACHE flags (via environment as no command line option available)
|
||||
CCACHE_SLOPPINESS ?= pch_defines,time_macros
|
||||
export CCACHE_SLOPPINESS
|
||||
|
||||
######################################################################
|
||||
#### Top level
|
||||
|
||||
@@ -151,16 +161,55 @@ maintainer-copy::
|
||||
#### Top executable
|
||||
|
||||
RAW_OBJS = \
|
||||
V3Const__gen.o \
|
||||
V3Error.o \
|
||||
V3FileLine.o \
|
||||
V3Graph.o \
|
||||
V3GraphAcyc.o \
|
||||
V3GraphAlg.o \
|
||||
V3GraphPathChecker.o \
|
||||
V3GraphTest.o \
|
||||
V3Hash.o \
|
||||
V3OptionParser.o \
|
||||
V3Os.o \
|
||||
V3ParseGrammar.o \
|
||||
V3ParseImp.o \
|
||||
V3ParseLex.o \
|
||||
V3PreProc.o \
|
||||
V3PreShell.o \
|
||||
V3String.o \
|
||||
V3ThreadPool.o \
|
||||
V3Waiver.o \
|
||||
Verilator.o \
|
||||
|
||||
RAW_OBJS_PCH_ASTMT = \
|
||||
V3Ast.o \
|
||||
V3AstNodes.o \
|
||||
V3Broken.o \
|
||||
V3Config.o \
|
||||
V3EmitCBase.o \
|
||||
V3EmitCConstPool.o \
|
||||
V3EmitCFunc.o \
|
||||
V3EmitCHeaders.o \
|
||||
V3EmitCImp.o \
|
||||
V3EmitCInlines.o \
|
||||
V3EmitCPch.o \
|
||||
V3EmitV.o \
|
||||
V3File.o \
|
||||
V3Global.o \
|
||||
V3Hasher.o \
|
||||
V3Number.o \
|
||||
V3Options.o \
|
||||
V3Stats.o \
|
||||
V3StatsReport.o \
|
||||
|
||||
RAW_OBJS_PCH_ASTNOMT = \
|
||||
V3Active.o \
|
||||
V3ActiveTop.o \
|
||||
V3Assert.o \
|
||||
V3AssertPre.o \
|
||||
V3Ast.o \
|
||||
V3AstNodes.o \
|
||||
V3Begin.o \
|
||||
V3Branch.o \
|
||||
V3Broken.o \
|
||||
V3CCtors.o \
|
||||
V3CUse.o \
|
||||
V3Case.o \
|
||||
@@ -170,8 +219,6 @@ RAW_OBJS = \
|
||||
V3Clock.o \
|
||||
V3Combine.o \
|
||||
V3Common.o \
|
||||
V3Config.o \
|
||||
V3Const__gen.o \
|
||||
V3Coverage.o \
|
||||
V3CoverageJoin.o \
|
||||
V3Dead.o \
|
||||
@@ -187,38 +234,21 @@ RAW_OBJS = \
|
||||
V3DfgPasses.o \
|
||||
V3DfgPeephole.o \
|
||||
V3DupFinder.o \
|
||||
V3EmitCBase.o \
|
||||
V3EmitCConstPool.o \
|
||||
V3EmitCFunc.o \
|
||||
V3EmitCHeaders.o \
|
||||
V3EmitCImp.o \
|
||||
V3EmitCInlines.o \
|
||||
V3EmitCMain.o \
|
||||
V3EmitCMake.o \
|
||||
V3EmitCModel.o \
|
||||
V3EmitCSyms.o \
|
||||
V3EmitMk.o \
|
||||
V3EmitV.o \
|
||||
V3EmitXml.o \
|
||||
V3Error.o \
|
||||
V3Expand.o \
|
||||
V3File.o \
|
||||
V3FileLine.o \
|
||||
V3Force.o \
|
||||
V3Fork.o \
|
||||
V3Gate.o \
|
||||
V3Global.o \
|
||||
V3Graph.o \
|
||||
V3GraphAcyc.o \
|
||||
V3GraphAlg.o \
|
||||
V3GraphPathChecker.o \
|
||||
V3GraphTest.o \
|
||||
V3Hash.o \
|
||||
V3Hasher.o \
|
||||
V3HierBlock.o \
|
||||
V3Inline.o \
|
||||
V3Inst.o \
|
||||
V3InstrCount.o \
|
||||
V3Interface.o \
|
||||
V3Life.o \
|
||||
V3LifePost.o \
|
||||
V3LinkCells.o \
|
||||
@@ -232,18 +262,9 @@ RAW_OBJS = \
|
||||
V3Localize.o \
|
||||
V3MergeCond.o \
|
||||
V3Name.o \
|
||||
V3Number.o \
|
||||
V3OptionParser.o \
|
||||
V3Options.o \
|
||||
V3Order.o \
|
||||
V3Os.o \
|
||||
V3Param.o \
|
||||
V3ParseGrammar.o \
|
||||
V3ParseImp.o \
|
||||
V3ParseLex.o \
|
||||
V3Partition.o \
|
||||
V3PreProc.o \
|
||||
V3PreShell.o \
|
||||
V3Premit.o \
|
||||
V3ProtectLib.o \
|
||||
V3Randomize.o \
|
||||
@@ -259,14 +280,10 @@ RAW_OBJS = \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
V3SplitVar.o \
|
||||
V3Stats.o \
|
||||
V3StatsReport.o \
|
||||
V3String.o \
|
||||
V3Subst.o \
|
||||
V3TSP.o \
|
||||
V3Table.o \
|
||||
V3Task.o \
|
||||
V3ThreadPool.o \
|
||||
V3Timing.o \
|
||||
V3Trace.o \
|
||||
V3TraceDecl.o \
|
||||
@@ -275,8 +292,8 @@ RAW_OBJS = \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3VariableOrder.o \
|
||||
V3Waiver.o \
|
||||
V3Width.o \
|
||||
V3WidthCommit.o \
|
||||
V3WidthSel.o \
|
||||
|
||||
# verilator_coverage
|
||||
@@ -284,21 +301,21 @@ VLCOV_OBJS = \
|
||||
VlcMain.o \
|
||||
|
||||
NON_STANDALONE_HEADERS = \
|
||||
V3AstInlines.h \
|
||||
V3AstNodeDType.h \
|
||||
V3AstNodeExpr.h \
|
||||
V3AstNodeOther.h \
|
||||
V3DfgVertices.h \
|
||||
V3AstInlines.h \
|
||||
V3AstNodeDType.h \
|
||||
V3AstNodeExpr.h \
|
||||
V3AstNodeOther.h \
|
||||
V3DfgVertices.h \
|
||||
V3ThreadPool.h \
|
||||
V3WidthCommit.h \
|
||||
V3WidthRemove.h \
|
||||
|
||||
AST_DEFS := \
|
||||
V3AstNodeDType.h \
|
||||
V3AstNodeExpr.h \
|
||||
V3AstNodeOther.h \
|
||||
V3AstNodeDType.h \
|
||||
V3AstNodeExpr.h \
|
||||
V3AstNodeOther.h \
|
||||
|
||||
DFG_DEFS := \
|
||||
V3DfgVertices.h
|
||||
V3DfgVertices.h
|
||||
|
||||
#### astgen common flags
|
||||
|
||||
@@ -310,7 +327,7 @@ ASTGENFLAGS += $(foreach f,$(DFG_DEFS),--dfgdef $f)
|
||||
|
||||
ifeq ($(VL_VLCOV),)
|
||||
PREDEP_H = V3Ast__gen_forward_class_decls.h
|
||||
OBJS += $(RAW_OBJS)
|
||||
OBJS += $(RAW_OBJS) $(RAW_OBJS_PCH_ASTMT) $(RAW_OBJS_PCH_ASTNOMT)
|
||||
else
|
||||
PREDEP_H =
|
||||
OBJS += $(VLCOV_OBJS)
|
||||
@@ -330,6 +347,8 @@ V3Number_test: V3Number_test.o
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
%.gch: %
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH} $< -o $@
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
%.o: %.c
|
||||
@@ -347,6 +366,22 @@ V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
||||
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
define CXX_ASTMT_template
|
||||
$(1): $(basename $(1)).cpp V3PchAstMT.h.gch
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH_I} V3PchAstMT.h${CFG_GCH_IF_CLANG} -c $(srcdir)/$(basename $(1)).cpp -o $(1)
|
||||
|
||||
endef
|
||||
|
||||
$(foreach obj,$(RAW_OBJS_PCH_ASTMT),$(eval $(call CXX_ASTMT_template,$(obj))))
|
||||
|
||||
define CXX_ASTNOMT_template
|
||||
$(1): $(basename $(1)).cpp V3PchAstNoMT.h.gch
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH_I} V3PchAstNoMT.h${CFG_GCH_IF_CLANG} -c $(srcdir)/$(basename $(1)).cpp -o $(1)
|
||||
|
||||
endef
|
||||
|
||||
$(foreach obj,$(RAW_OBJS_PCH_ASTNOMT),$(eval $(call CXX_ASTNOMT_template,$(obj))))
|
||||
|
||||
#### Generated files
|
||||
|
||||
# Target rule called before parallel build to make generated files
|
||||
@@ -389,7 +424,7 @@ HEADER_CC_H := $(filter-out $(NON_STANDALONE_HEADERS), $(notdir $(wildcard $(src
|
||||
header_cc: $(addsuffix __header_cc.o, $(basename $(HEADER_CC_H)))
|
||||
|
||||
%__header_cc.cpp: %.h
|
||||
$(PYTHON3) $(srcdir)/../bin/verilator_includer $^ > $@
|
||||
$(PYTHON3) $(srcdir)/../bin/verilator_includer -DVL_MT_DISABLED_CODE_UNIT=1 $^ > $@
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
|
||||
+1
-4
@@ -26,14 +26,11 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Active.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Graph.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Active final {
|
||||
public:
|
||||
static void activeAll(AstNetlist* nodep);
|
||||
static void activeAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-4
@@ -23,14 +23,11 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3ActiveTop.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3SenTree.h"
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3ActiveTop final {
|
||||
public:
|
||||
static void activeTopAll(AstNetlist* nodep);
|
||||
static void activeTopAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+10
-14
@@ -14,14 +14,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Assert.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
@@ -158,7 +154,7 @@ private:
|
||||
if (m_procedurep) {
|
||||
// To support this need queue of asserts to activate
|
||||
nodep->v3error("Unsupported: Procedural concurrent assertion with"
|
||||
" clocking event inside always (IEEE 1800-2917 16.14.6)");
|
||||
" clocking event inside always (IEEE 1800-2017 16.14.6)");
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -243,7 +239,7 @@ private:
|
||||
}
|
||||
|
||||
// Build a bitmask of the true predicates
|
||||
AstNodeExpr* const predp = ifp->condp()->cloneTree(false);
|
||||
AstNodeExpr* const predp = ifp->condp()->cloneTreePure(false);
|
||||
if (propp) {
|
||||
propp = new AstConcat{nodep->fileline(), predp, propp};
|
||||
} else {
|
||||
@@ -312,17 +308,17 @@ private:
|
||||
icondp = VN_AS(icondp->nextp(), NodeExpr)) {
|
||||
AstNodeExpr* onep;
|
||||
if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) {
|
||||
onep = rcondp->newAndFromInside(nodep->exprp(),
|
||||
rcondp->lhsp()->cloneTree(true),
|
||||
rcondp->rhsp()->cloneTree(true));
|
||||
onep = rcondp->newAndFromInside(
|
||||
nodep->exprp(), rcondp->lhsp()->cloneTreePure(true),
|
||||
rcondp->rhsp()->cloneTreePure(true));
|
||||
} else if (nodep->casex() || nodep->casez() || nodep->caseInside()) {
|
||||
onep = AstEqWild::newTyped(itemp->fileline(),
|
||||
nodep->exprp()->cloneTree(false),
|
||||
icondp->cloneTree(false));
|
||||
nodep->exprp()->cloneTreePure(false),
|
||||
icondp->cloneTreePure(false));
|
||||
} else {
|
||||
onep = AstEq::newTyped(icondp->fileline(),
|
||||
nodep->exprp()->cloneTree(false),
|
||||
icondp->cloneTree(false));
|
||||
nodep->exprp()->cloneTreePure(false),
|
||||
icondp->cloneTreePure(false));
|
||||
}
|
||||
if (propp) {
|
||||
propp = new AstConcat{icondp->fileline(), onep, propp};
|
||||
|
||||
+2
-1
@@ -21,12 +21,13 @@
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Assert final {
|
||||
public:
|
||||
static void assertAll(AstNetlist* nodep);
|
||||
static void assertAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+10
-13
@@ -15,18 +15,15 @@
|
||||
//*************************************************************************
|
||||
// Pre steps:
|
||||
// Attach clocks to each assertion
|
||||
// Substitute property references by property body (IEEE Std 1800-2012, section 16.12.1).
|
||||
// Substitute property references by property body (IEEE 1800-2012 16.12.1).
|
||||
// Transform clocking blocks into imperative logic
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3AssertPre.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Task.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
@@ -177,7 +174,7 @@ private:
|
||||
if (nodep->direction() == VDirection::OUTPUT) {
|
||||
AstVarRef* const skewedRefp = new AstVarRef{flp, varp, VAccess::READ};
|
||||
skewedRefp->user1(true);
|
||||
AstAssign* const assignp = new AstAssign{flp, exprp->cloneTree(false), skewedRefp};
|
||||
AstAssign* const assignp = new AstAssign{flp, exprp->cloneTreePure(false), skewedRefp};
|
||||
if (skewp->isZero()) {
|
||||
// Drive the var in Re-NBA (IEEE 1800-2017 14.16)
|
||||
m_clockingp->addNextHere(new AstAlwaysReactive{
|
||||
@@ -208,12 +205,12 @@ private:
|
||||
refp->user1(true);
|
||||
if (skewp->num().is1Step()) {
|
||||
// Assign the sampled expression to the clockvar (IEEE 1800-2017 14.13)
|
||||
AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTree(false)};
|
||||
AstSampled* const sampledp = new AstSampled{flp, exprp->cloneTreePure(false)};
|
||||
sampledp->dtypeFrom(exprp);
|
||||
m_clockingp->addNextHere(new AstAssignW{flp, refp, sampledp});
|
||||
} else if (skewp->isZero()) {
|
||||
// #0 means the var has to be sampled in Observed (IEEE 1800-2017 14.13)
|
||||
AstAssign* const assignp = new AstAssign{flp, refp, exprp->cloneTree(false)};
|
||||
AstAssign* const assignp = new AstAssign{flp, refp, exprp->cloneTreePure(false)};
|
||||
m_clockingp->addNextHere(new AstAlwaysObserved{
|
||||
flp, new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)}, assignp});
|
||||
} else {
|
||||
@@ -230,7 +227,7 @@ private:
|
||||
AstCMethodHard* const pushp = new AstCMethodHard{
|
||||
flp, new AstVarRef{flp, queueVarp, VAccess::WRITE}, "push",
|
||||
new AstTime{nodep->fileline(), m_modp->timeunit()}};
|
||||
pushp->addPinsp(exprp->cloneTree(false));
|
||||
pushp->addPinsp(exprp->cloneTreePure(false));
|
||||
pushp->dtypeSetVoid();
|
||||
m_clockingp->addNextHere(
|
||||
new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, pushp->makeStmt()});
|
||||
@@ -372,7 +369,7 @@ private:
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTree(false)}};
|
||||
exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTreePure(false)}};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
@@ -393,7 +390,7 @@ private:
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTree(false)};
|
||||
exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTreePure(false)};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
@@ -408,7 +405,7 @@ private:
|
||||
if (sentreep) sentreep->unlinkFrBack();
|
||||
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq{fl, past, exprp->cloneTree(false)};
|
||||
exprp = new AstEq{fl, past, exprp->cloneTreePure(false)};
|
||||
exprp->dtypeSetBit();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep, sentreep));
|
||||
@@ -442,7 +439,7 @@ private:
|
||||
// Block is the new expression to evaluate
|
||||
AstNodeExpr* blockp = VN_AS(nodep->propp()->unlinkFrBack(), NodeExpr);
|
||||
if (AstNodeExpr* const disablep = nodep->disablep()) {
|
||||
m_disablep = disablep->cloneTree(false);
|
||||
m_disablep = disablep->cloneTreePure(false);
|
||||
if (VN_IS(nodep->backp(), Cover)) {
|
||||
blockp = new AstAnd{disablep->fileline(),
|
||||
new AstNot{disablep->fileline(), disablep->unlinkFrBack()},
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3AssertPre final {
|
||||
public:
|
||||
static void assertPreAll(AstNetlist* nodep);
|
||||
static void assertPreAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+121
-37
@@ -14,16 +14,11 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3PchAstMT.h"
|
||||
|
||||
#include "V3Broken.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3String.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
@@ -33,6 +28,8 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
//======================================================================
|
||||
// Statics
|
||||
|
||||
uint64_t VIsCached::s_cachedCntGbl = 1;
|
||||
|
||||
uint64_t AstNode::s_editCntLast = 0;
|
||||
uint64_t AstNode::s_editCntGbl = 0; // Hot cache line
|
||||
|
||||
@@ -44,13 +41,11 @@ uint32_t VNUser1InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
|
||||
uint32_t VNUser2InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
|
||||
uint32_t VNUser3InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
|
||||
uint32_t VNUser4InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
|
||||
uint32_t VNUser5InUse::s_userCntGbl = 0; // Hot cache line, leave adjacent
|
||||
|
||||
bool VNUser1InUse::s_userBusy = false;
|
||||
bool VNUser2InUse::s_userBusy = false;
|
||||
bool VNUser3InUse::s_userBusy = false;
|
||||
bool VNUser4InUse::s_userBusy = false;
|
||||
bool VNUser5InUse::s_userBusy = false;
|
||||
|
||||
int AstNodeDType::s_uniqueNum = 0;
|
||||
|
||||
@@ -372,8 +367,8 @@ AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp) {
|
||||
|
||||
void AstNode::addNextHere(AstNode* newp) {
|
||||
// Add to m_nextp on exact node passed, not at the end.
|
||||
// This could be at head, tail, or both (single)
|
||||
// New could be head of single node, or list
|
||||
// 'this' could be at head, tail, or both (single)
|
||||
// 'newp' could be head of single node, or list
|
||||
UASSERT(newp, "Null item passed to addNext");
|
||||
UASSERT_OBJ(!newp->backp(), newp, "New node (back) already assigned?");
|
||||
debugTreeChange(this, "-addHereThs: ", __LINE__, false);
|
||||
@@ -799,26 +794,34 @@ void AstNode::swapWith(AstNode* bp) {
|
||||
//======================================================================
|
||||
// Clone
|
||||
|
||||
AstNode* AstNode::cloneTreeIter() {
|
||||
AstNode* AstNode::cloneTreeIter(bool needPure) {
|
||||
// private: Clone single node and children
|
||||
if (VL_UNLIKELY(needPure && !isPure())) {
|
||||
this->v3warn(SIDEEFFECT,
|
||||
"Expression side effect may be mishandled\n"
|
||||
<< this->warnMore()
|
||||
<< "... Suggest use a temporary variable in place of this expression");
|
||||
// this->v3fatalSrc("cloneTreePure debug backtrace"); // Comment in to debug where caused
|
||||
// it
|
||||
}
|
||||
AstNode* const newp = this->clone();
|
||||
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList());
|
||||
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList());
|
||||
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList());
|
||||
if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList());
|
||||
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList(needPure));
|
||||
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList(needPure));
|
||||
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList(needPure));
|
||||
if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList(needPure));
|
||||
newp->m_iterpp = nullptr;
|
||||
newp->clonep(this); // Save pointers to/from both to simplify relinking.
|
||||
this->clonep(newp); // Save pointers to/from both to simplify relinking.
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstNode* AstNode::cloneTreeIterList() {
|
||||
AstNode* AstNode::cloneTreeIterList(bool needPure) {
|
||||
// private: Clone list of nodes, set m_headtailp
|
||||
AstNode* newheadp = nullptr;
|
||||
AstNode* newtailp = nullptr;
|
||||
// Audited to make sure this is never nullptr
|
||||
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
|
||||
AstNode* const newp = oldp->cloneTreeIter();
|
||||
AstNode* const newp = oldp->cloneTreeIter(needPure);
|
||||
newp->m_headtailp = nullptr;
|
||||
newp->m_backp = newtailp;
|
||||
if (newtailp) newtailp->m_nextp = newp;
|
||||
@@ -830,14 +833,14 @@ AstNode* AstNode::cloneTreeIterList() {
|
||||
return newheadp;
|
||||
}
|
||||
|
||||
AstNode* AstNode::cloneTree(bool cloneNextLink) {
|
||||
AstNode* AstNode::cloneTree(bool cloneNextLink, bool needPure) {
|
||||
debugTreeChange(this, "-cloneThs: ", __LINE__, cloneNextLink);
|
||||
cloneClearTree();
|
||||
AstNode* newp;
|
||||
if (cloneNextLink && this->m_nextp) {
|
||||
newp = cloneTreeIterList();
|
||||
newp = cloneTreeIterList(needPure);
|
||||
} else {
|
||||
newp = cloneTreeIter();
|
||||
newp = cloneTreeIter(needPure);
|
||||
newp->m_nextp = nullptr;
|
||||
newp->m_headtailp = newp;
|
||||
}
|
||||
@@ -1230,7 +1233,6 @@ void AstNode::dumpPtrs(std::ostream& os) const {
|
||||
if (user2p()) os << " user2p=" << cvtToHex(user2p());
|
||||
if (user3p()) os << " user3p=" << cvtToHex(user3p());
|
||||
if (user4p()) os << " user4p=" << cvtToHex(user4p());
|
||||
if (user5p()) os << " user5p=" << cvtToHex(user5p());
|
||||
if (m_iterpp) {
|
||||
os << " iterpp=" << cvtToHex(m_iterpp);
|
||||
// This may cause address sanitizer failures as iterpp can be stale
|
||||
@@ -1343,38 +1345,24 @@ void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump)
|
||||
}
|
||||
}
|
||||
|
||||
bool AstNode::isTreePureRecurse() const {
|
||||
// Should memoize this if call commonly
|
||||
if (!this->isPure()) return false;
|
||||
if (this->op1p() && !this->op1p()->isTreePureRecurse()) return false;
|
||||
if (this->op2p() && !this->op2p()->isTreePureRecurse()) return false;
|
||||
if (this->op3p() && !this->op3p()->isTreePureRecurse()) return false;
|
||||
if (this->op4p() && !this->op4p()->isTreePureRecurse()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
string AstNode::instanceStr() const {
|
||||
// Max iterations before giving up on location search,
|
||||
// in case we have some circular reference bug.
|
||||
constexpr unsigned maxIterations = 10000;
|
||||
unsigned iterCount = 0;
|
||||
|
||||
for (const AstNode* backp = this; backp; backp = backp->backp(), ++iterCount) {
|
||||
if (VL_UNCOVERABLE(iterCount >= maxIterations)) return ""; // LCOV_EXCL_LINE
|
||||
|
||||
// Prefer the enclosing scope, if there is one. This is always under the enclosing module,
|
||||
// so just pick it up when encountered
|
||||
if (const AstScope* const scopep = VN_CAST(backp, Scope)) {
|
||||
return scopep->isTop() ? "" : "... In instance " + scopep->prettyName();
|
||||
return scopep->isTop() ? "" : "... note: In instance " + scopep->prettyNameQ();
|
||||
}
|
||||
|
||||
// If scopes don't exist, report an example instance of the enclosing module
|
||||
if (const AstModule* const modp = VN_CAST(backp, Module)) {
|
||||
const string instanceName = modp->someInstanceName();
|
||||
return instanceName.empty() ? "" : "... In instance " + instanceName;
|
||||
return instanceName.empty() ? "" : "... note: In instance '" + instanceName + "'";
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
void AstNode::v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) {
|
||||
@@ -1473,6 +1461,102 @@ AstNodeDType* AstNode::findStreamDType() const {
|
||||
return v3Global.rootp()->typeTablep()->findStreamDType(fileline());
|
||||
}
|
||||
|
||||
static const AstNodeDType* computeCastableBase(const AstNodeDType* nodep) {
|
||||
while (true) {
|
||||
if (const AstPackArrayDType* const packp = VN_CAST(nodep, PackArrayDType)) {
|
||||
nodep = packp->subDTypep();
|
||||
continue;
|
||||
} else if (const AstNodeDType* const refp = nodep->skipRefToEnump()) {
|
||||
if (refp != nodep) {
|
||||
nodep = refp;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
}
|
||||
|
||||
static VCastable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
const AstNode* fromConstp) {
|
||||
const VCastable castable = VCastable::UNSUPPORTED;
|
||||
toDtp = toDtp->skipRefToEnump();
|
||||
fromDtp = fromDtp->skipRefToEnump();
|
||||
if (toDtp == fromDtp) return VCastable::SAMEISH;
|
||||
if (toDtp->similarDType(fromDtp)) return VCastable::SAMEISH;
|
||||
// UNSUP unpacked struct/unions (treated like BasicDType)
|
||||
const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp);
|
||||
|
||||
const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType) || VN_IS(fromBaseDtp, EnumDType)
|
||||
|| VN_IS(fromBaseDtp, StreamDType)
|
||||
|| VN_IS(fromBaseDtp, NodeUOrStructDType);
|
||||
|
||||
const AstNodeDType* toBaseDtp = computeCastableBase(toDtp);
|
||||
const bool toNumericable
|
||||
= VN_IS(toBaseDtp, BasicDType) || VN_IS(toBaseDtp, NodeUOrStructDType);
|
||||
|
||||
if (toBaseDtp == fromBaseDtp) {
|
||||
return VCastable::COMPATIBLE;
|
||||
} else if (toNumericable) {
|
||||
if (fromNumericable) return VCastable::COMPATIBLE;
|
||||
} else if (VN_IS(toDtp, EnumDType)) {
|
||||
if (VN_IS(fromBaseDtp, EnumDType) && toDtp->sameTree(fromDtp))
|
||||
return VCastable::ENUM_IMPLICIT;
|
||||
if (fromNumericable) return VCastable::ENUM_EXPLICIT;
|
||||
} else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromConstp, Const)) {
|
||||
if (VN_IS(fromConstp, Const) && VN_AS(fromConstp, Const)->num().isNull())
|
||||
return VCastable::COMPATIBLE;
|
||||
} else if (VN_IS(toDtp, ClassRefDType) && VN_IS(fromDtp, ClassRefDType)) {
|
||||
const auto toClassp = VN_AS(toDtp, ClassRefDType)->classp();
|
||||
const auto fromClassp = VN_AS(fromDtp, ClassRefDType)->classp();
|
||||
const bool downcast = AstClass::isClassExtendedFrom(toClassp, fromClassp);
|
||||
const bool upcast = AstClass::isClassExtendedFrom(fromClassp, toClassp);
|
||||
if (upcast) {
|
||||
return VCastable::COMPATIBLE;
|
||||
} else if (downcast) {
|
||||
return VCastable::DYNAMIC_CLASS;
|
||||
} else {
|
||||
return VCastable::INCOMPATIBLE;
|
||||
}
|
||||
}
|
||||
return castable;
|
||||
}
|
||||
|
||||
VCastable AstNode::computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
const AstNode* fromConstp) {
|
||||
const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp);
|
||||
UINFO(9, " castable=" << castable << " for " << toDtp << endl);
|
||||
UINFO(9, " =?= " << fromDtp << endl);
|
||||
UINFO(9, " const= " << fromConstp << endl);
|
||||
return castable;
|
||||
}
|
||||
|
||||
AstNodeDType* AstNode::getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) {
|
||||
// Return the class type that both nodep1 and nodep2 are castable to.
|
||||
// If both are null, return the type of null constant.
|
||||
// If one is a class and one is null, return AstClassRefDType that points to that class.
|
||||
// If no common class type exists, return nullptr.
|
||||
|
||||
// First handle cases with null values and when one class is a super class of the other.
|
||||
if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2);
|
||||
{
|
||||
const VCastable castable = computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2);
|
||||
if (castable == VCastable::SAMEISH || castable == VCastable::COMPATIBLE) {
|
||||
return nodep1->dtypep();
|
||||
} else if (castable == VCastable::DYNAMIC_CLASS) {
|
||||
return nodep2->dtypep();
|
||||
}
|
||||
}
|
||||
|
||||
AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType);
|
||||
while (classDtypep1) {
|
||||
const VCastable castable = computeCastable(classDtypep1, nodep2->dtypep(), nodep2);
|
||||
if (castable == VCastable::COMPATIBLE) return classDtypep1;
|
||||
AstClassExtends* const extendsp = classDtypep1->classp()->extendsp();
|
||||
classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// VNDeleter
|
||||
|
||||
|
||||
+254
-53
@@ -167,6 +167,37 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VIsCached final {
|
||||
// Used in some nodes to cache results of boolean methods
|
||||
// If cachedCnt == 0, not cached
|
||||
// else if cachedCnt == s_cachedCntGbl, then m_state is if cached
|
||||
uint64_t m_cachedCnt : 63; // Mark of when cache was computed
|
||||
uint64_t m_state : 1;
|
||||
static uint64_t s_cachedCntGbl; // Global computed count
|
||||
|
||||
public:
|
||||
VIsCached()
|
||||
: m_cachedCnt{0}
|
||||
, m_state{0} {}
|
||||
bool isCached() const { return m_cachedCnt == s_cachedCntGbl; }
|
||||
bool get() const { return m_state; }
|
||||
void set(bool flag) {
|
||||
m_cachedCnt = s_cachedCntGbl;
|
||||
m_state = flag;
|
||||
}
|
||||
void clearCache() {
|
||||
m_cachedCnt = 0;
|
||||
m_state = 0;
|
||||
}
|
||||
static void clearCacheTree() {
|
||||
++s_cachedCntGbl;
|
||||
// 64 bits so won't overflow
|
||||
// UASSERT_STATIC(s_cachedCntGbl < MAX_CNT, "Overflow of cache counting");
|
||||
}
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VAccess final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
@@ -293,7 +324,7 @@ public:
|
||||
ET_BOTHEDGE, // POSEDGE | NEGEDGE (i.e.: 'edge' in Verilog)
|
||||
ET_POSEDGE,
|
||||
ET_NEGEDGE,
|
||||
ET_EVENT, // VlEvent::isFired
|
||||
ET_EVENT, // VlEventBase::isFired
|
||||
// Involving an expression
|
||||
ET_TRUE,
|
||||
//
|
||||
@@ -644,6 +675,39 @@ public:
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
const char* traceSigType() const {
|
||||
// VerilatedTraceSigType to used in trace signal declaration
|
||||
static const char* const lut[] = {
|
||||
/* UNKNOWN: */ "", // Should not be traced
|
||||
/* BIT: */ "BIT",
|
||||
/* BYTE: */ "BYTE",
|
||||
/* CHANDLE: */ "",
|
||||
/* EVENT: */ "EVENT",
|
||||
/* INT: */ "INT",
|
||||
/* INTEGER: */ "INTEGER",
|
||||
/* LOGIC: */ "LOGIC",
|
||||
/* LONGINT: */ "LONGINT",
|
||||
/* DOUBLE: */ "DOUBLE",
|
||||
/* SHORTINT: */ "SHORTINT",
|
||||
/* TIME: */ "TIME",
|
||||
/* STRING: */ "",
|
||||
/* UNTYPED: */ "", // Should not be traced
|
||||
/* SCOPEPTR: */ "", // Should not be traced
|
||||
/* CHARPTR: */ "", // Should not be traced
|
||||
/* MTASKSTATE: */ "", // Should not be traced
|
||||
/* TRIGGERVEC: */ "", // Should not be traced
|
||||
/* DELAY_SCHEDULER: */ "", // Should not be traced
|
||||
/* TRIGGER_SCHEDULER: */ "", // Should not be traced
|
||||
/* DYNAMIC_TRIGGER_SCHEDULER: */ "", // Should not be traced
|
||||
/* FORK_SYNC: */ "", // Should not be traced
|
||||
/* PROCESS_REFERENCE: */ "", // Should not be traced
|
||||
/* UINT32: */ "BIT",
|
||||
/* UINT64: */ "BIT",
|
||||
/* LOGIC_IMPLICIT: */ "", // Should not be traced
|
||||
};
|
||||
return lut[m_e];
|
||||
}
|
||||
};
|
||||
constexpr bool operator==(const VBasicDTypeKwd& lhs, const VBasicDTypeKwd& rhs) VL_MT_SAFE {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
@@ -690,7 +754,8 @@ public:
|
||||
}
|
||||
bool isReadOnly() const VL_MT_SAFE { return m_e == INPUT || m_e == CONSTREF; }
|
||||
bool isWritable() const VL_MT_SAFE { return m_e == OUTPUT || m_e == INOUT || m_e == REF; }
|
||||
bool isRefOrConstRef() const VL_MT_SAFE { return m_e == REF || m_e == CONSTREF; }
|
||||
bool isRef() const VL_MT_SAFE { return m_e == REF; }
|
||||
bool isConstRef() const VL_MT_SAFE { return m_e == CONSTREF; }
|
||||
};
|
||||
constexpr bool operator==(const VDirection& lhs, const VDirection& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
@@ -790,7 +855,6 @@ public:
|
||||
SUPPLY1,
|
||||
WIRE,
|
||||
WREAL,
|
||||
IMPLICITWIRE,
|
||||
TRIWIRE,
|
||||
TRI0,
|
||||
TRI1,
|
||||
@@ -810,26 +874,25 @@ public:
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[] = {
|
||||
"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
|
||||
"WIRE", "WREAL", "IMPLICITWIRE", "TRIWIRE", "TRI0", "TRI1", "PORT",
|
||||
"BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
||||
static const char* const names[]
|
||||
= {"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1",
|
||||
"WIRE", "WREAL", "TRIWIRE", "TRI0", "TRI1", "PORT", "BLOCKTEMP",
|
||||
"MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"};
|
||||
return names[m_e];
|
||||
}
|
||||
bool isParam() const { return m_e == GPARAM || m_e == LPARAM; }
|
||||
bool isSignal() const {
|
||||
return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0
|
||||
|| m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
|
||||
return (m_e == WIRE || m_e == WREAL || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|
||||
|| m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR);
|
||||
}
|
||||
bool isNet() const {
|
||||
return (m_e == WIRE || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|
||||
|| m_e == SUPPLY0 || m_e == SUPPLY1);
|
||||
return (m_e == WIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == SUPPLY0
|
||||
|| m_e == SUPPLY1);
|
||||
}
|
||||
bool isContAssignable() const { // In Verilog, always ok in SystemVerilog
|
||||
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL
|
||||
|| m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1
|
||||
|| m_e == PORT || m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP
|
||||
|| m_e == XTEMP || m_e == IFACEREF);
|
||||
return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == TRIWIRE
|
||||
|| m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == BLOCKTEMP
|
||||
|| m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP || m_e == IFACEREF);
|
||||
}
|
||||
bool isProcAssignable() const {
|
||||
return (m_e == GPARAM || m_e == LPARAM || m_e == GENVAR || m_e == VAR || m_e == BLOCKTEMP
|
||||
@@ -843,6 +906,32 @@ public:
|
||||
return (m_e == VAR || m_e == GPARAM || m_e == LPARAM || m_e == PORT || m_e == WIRE
|
||||
|| m_e == TRI0 || m_e == TRI1);
|
||||
}
|
||||
|
||||
const char* traceSigKind() const {
|
||||
// VerilatedTraceSigKind to used in trace signal declaration
|
||||
static const char* const lut[] = {
|
||||
/* UNKNOWN: */ "", // Should not be traced
|
||||
/* GPARAM: */ "PARAMETER",
|
||||
/* LPARAM: */ "PARAMETER",
|
||||
/* GENVAR: */ "PARAMETER",
|
||||
/* VAR: */ "VAR",
|
||||
/* SUPPLY0: */ "SUPPLY0",
|
||||
/* SUPPLY1: */ "SUPPLY1",
|
||||
/* WIRE: */ "WIRE",
|
||||
/* WREAL: */ "WIRE",
|
||||
/* TRIWIRE: */ "TRI",
|
||||
/* TRI0: */ "TRI0",
|
||||
/* TRI1: */ "TRI1",
|
||||
/* PORT: */ "WIRE",
|
||||
/* BLOCKTEMP: */ "VAR",
|
||||
/* MODULETEMP: */ "VAR",
|
||||
/* STMTTEMP: */ "VAR",
|
||||
/* XTEMP: */ "VAR",
|
||||
/* IFACEREF: */ "", // Should not be traced directly
|
||||
/* MEMBER: */ "VAR",
|
||||
};
|
||||
return lut[m_e];
|
||||
}
|
||||
};
|
||||
constexpr bool operator==(const VVarType& lhs, const VVarType& rhs) VL_MT_SAFE {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
@@ -1215,6 +1304,116 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VTraceType final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
CONSTANT, // Constant value dump (once at the beginning)
|
||||
FULL, // Full value dump (always emitted)
|
||||
CHANGE // Incremental value dump (emitted only if the value changed)
|
||||
};
|
||||
enum en m_e;
|
||||
VTraceType()
|
||||
: m_e{CONSTANT} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VTraceType(en _e)
|
||||
: m_e{_e} {}
|
||||
explicit VTraceType(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[] = {"CONSTANT", "FULL", "CHANGE"};
|
||||
return names[m_e];
|
||||
}
|
||||
};
|
||||
constexpr bool operator==(const VTraceType& lhs, const VTraceType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VTraceType& lhs, VTraceType::en rhs) { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VTraceType::en lhs, const VTraceType& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VTraceType& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VTracePrefixType final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
// Note: Entries must match VerilatedTracePrefixType
|
||||
ARRAY_PACKED,
|
||||
ARRAY_UNPACKED,
|
||||
SCOPE_MODULE,
|
||||
SCOPE_INTERFACE,
|
||||
STRUCT_PACKED,
|
||||
STRUCT_UNPACKED,
|
||||
UNION_PACKED,
|
||||
};
|
||||
enum en m_e;
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VTracePrefixType(en _e)
|
||||
: m_e{_e} {}
|
||||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[]
|
||||
= {"ARRAY_PACKED", "ARRAY_UNPACKED", "SCOPE_MODULE", "SCOPE_INTERFACE",
|
||||
"STRUCT_PACKED", "STRUCT_UNPACKED", "UNION_PACKED"};
|
||||
return names[m_e];
|
||||
}
|
||||
};
|
||||
constexpr bool operator==(const VTracePrefixType& lhs, const VTracePrefixType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VTracePrefixType& lhs, VTracePrefixType::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
constexpr bool operator==(VTracePrefixType::en lhs, const VTracePrefixType& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& os, const VTracePrefixType& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VCastable final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
UNSUPPORTED,
|
||||
SAMEISH,
|
||||
COMPATIBLE,
|
||||
ENUM_EXPLICIT,
|
||||
ENUM_IMPLICIT,
|
||||
DYNAMIC_CLASS,
|
||||
INCOMPATIBLE,
|
||||
_ENUM_MAX // Leave last
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* const names[]
|
||||
= {"UNSUPPORTED", "SAMEISH", "COMPATIBLE", "ENUM_EXPLICIT",
|
||||
"ENUM_IMPLICIT", "DYNAMIC_CLASS", "INCOMPATIBLE"};
|
||||
return names[m_e];
|
||||
}
|
||||
VCastable()
|
||||
: m_e{UNSUPPORTED} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VCastable(en _e)
|
||||
: m_e{_e} {}
|
||||
explicit VCastable(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
};
|
||||
constexpr bool operator==(const VCastable& lhs, const VCastable& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VCastable& lhs, VCastable::en rhs) { return lhs.m_e == rhs; }
|
||||
constexpr bool operator==(VCastable::en lhs, const VCastable& rhs) { return lhs == rhs.m_e; }
|
||||
inline std::ostream& operator<<(std::ostream& os, const VCastable& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
|
||||
class VBasicTypeKey final {
|
||||
@@ -1412,17 +1611,6 @@ public:
|
||||
static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
};
|
||||
class VNUser5InUse final : VNUserInUseBase {
|
||||
protected:
|
||||
friend class AstNode;
|
||||
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
||||
static bool s_userBusy; // Count is in use
|
||||
public:
|
||||
VNUser5InUse() { allocate(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
~VNUser5InUse() { free (5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void clear() { clearcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void check() { checkcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
//######################################################################
|
||||
@@ -1431,7 +1619,7 @@ public:
|
||||
// nodes needs to be deferred to a later time, because pointers to the
|
||||
// removed nodes might still exist.
|
||||
|
||||
class VNDeleter VL_NOT_FINAL {
|
||||
class VNDeleter final {
|
||||
// MEMBERS
|
||||
std::vector<AstNode*> m_deleteps; // Nodes to delete
|
||||
|
||||
@@ -1444,11 +1632,11 @@ public:
|
||||
m_deleteps.push_back(nodep);
|
||||
}
|
||||
|
||||
// Delete all previously pushed nodes (by callint deleteTree)
|
||||
// Delete all previously pushed nodes (by calling deleteTree)
|
||||
void doDeletes();
|
||||
|
||||
// Do the deletions on destruction
|
||||
virtual ~VNDeleter() { doDeletes(); }
|
||||
~VNDeleter() { doDeletes(); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -1457,7 +1645,7 @@ public:
|
||||
// This only has the constant fuctions for non-modifying visitors.
|
||||
// For more typical usage see VNVisitor
|
||||
|
||||
class VNVisitorConst VL_NOT_FINAL : public VNDeleter {
|
||||
class VNVisitorConst VL_NOT_FINAL {
|
||||
friend class AstNode;
|
||||
|
||||
public:
|
||||
@@ -1475,6 +1663,7 @@ public:
|
||||
inline void iterateAndNextConstNullBackwards(AstNode* nodep);
|
||||
|
||||
virtual void visit(AstNode* nodep) = 0;
|
||||
virtual ~VNVisitorConst() {}
|
||||
#include "V3Ast__gen_visitor_decls.h" // From ./astgen
|
||||
};
|
||||
|
||||
@@ -1483,6 +1672,7 @@ public:
|
||||
// type without changing the base classes. See "Modern C++ Design".
|
||||
|
||||
class VNVisitor VL_NOT_FINAL : public VNVisitorConst {
|
||||
VNDeleter m_deleter; // Used to delay deletion of nodes
|
||||
public:
|
||||
/// Call visit()s on nodep
|
||||
inline void iterate(AstNode* nodep);
|
||||
@@ -1494,6 +1684,10 @@ public:
|
||||
inline void iterateAndNextNull(AstNode* nodep);
|
||||
/// Return edited nodep; see comments in V3Ast.cpp
|
||||
inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep);
|
||||
|
||||
VNDeleter& deleter() { return m_deleter; }
|
||||
void pushDeletep(AstNode* nodep) { deleter().pushDeletep(nodep); }
|
||||
void doDeletes() { deleter().doDeletes(); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -1620,8 +1814,6 @@ class AstNode VL_NOT_FINAL {
|
||||
uint32_t m_user3Cnt = 0; // Mark of when userp was set
|
||||
uint32_t m_user4Cnt = 0; // Mark of when userp was set
|
||||
VNUser m_user4u{0}; // Contains any information the user iteration routine wants
|
||||
VNUser m_user5u{0}; // Contains any information the user iteration routine wants
|
||||
uint32_t m_user5Cnt = 0; // Mark of when userp was set
|
||||
|
||||
// METHODS
|
||||
void op1p(AstNode* nodep) {
|
||||
@@ -1642,8 +1834,8 @@ class AstNode VL_NOT_FINAL {
|
||||
}
|
||||
|
||||
private:
|
||||
AstNode* cloneTreeIter();
|
||||
AstNode* cloneTreeIterList();
|
||||
AstNode* cloneTreeIter(bool needPure);
|
||||
AstNode* cloneTreeIterList(bool needPure);
|
||||
void checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE;
|
||||
bool gateTreeIter() const;
|
||||
static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
|
||||
@@ -1696,6 +1888,9 @@ protected:
|
||||
UASSERT_STATIC(s_cloneCntGbl, "Rollover");
|
||||
}
|
||||
|
||||
// Use instead isSame(), this is for each Ast* class, and assumes node is of same type
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
|
||||
public:
|
||||
// ACCESSORS
|
||||
VNType type() const VL_MT_SAFE { return m_type; }
|
||||
@@ -1808,6 +2003,7 @@ public:
|
||||
inline bool isDouble() const VL_MT_STABLE;
|
||||
inline bool isSigned() const VL_MT_STABLE;
|
||||
inline bool isString() const VL_MT_STABLE;
|
||||
inline bool isEvent() const VL_MT_STABLE;
|
||||
|
||||
// clang-format off
|
||||
VNUser user1u() const VL_MT_STABLE {
|
||||
@@ -1865,26 +2061,13 @@ public:
|
||||
int user4Inc(int val = 1) { int v = user4(); user4(v + val); return v; }
|
||||
int user4SetOnce() { int v = user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc()
|
||||
static void user4ClearTree() { VNUser4InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
VNUser user5u() const VL_MT_STABLE {
|
||||
// Slows things down measurably, so disabled by default
|
||||
//UASSERT_STATIC(VNUser5InUse::s_userBusy, "user5p used without AstUserInUse");
|
||||
return ((m_user5Cnt == VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0});
|
||||
}
|
||||
AstNode* user5p() const VL_MT_STABLE { return user5u().toNodep(); }
|
||||
void user5u(const VNUser& user) { m_user5u = user; m_user5Cnt = VNUser5InUse::s_userCntGbl; }
|
||||
void user5p(void* userp) { user5u(VNUser{userp}); }
|
||||
void user5(int val) { user5u(VNUser{val}); }
|
||||
int user5() const { return user5u().toInt(); }
|
||||
int user5Inc(int val = 1) { int v = user5(); user5(v + val); return v; }
|
||||
int user5SetOnce() { int v = user5(); if (!v) user5(1); return v; } // Better for cache than user5Inc()
|
||||
static void user5ClearTree() { VNUser5InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
// clang-format on
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
uint64_t editCount() const { return m_editCount; }
|
||||
void editCountInc() {
|
||||
m_editCount = ++s_editCntGbl; // Preincrement, so can "watch AstNode::s_editCntGbl=##"
|
||||
VIsCached::clearCacheTree(); // Any edit clears all caching
|
||||
}
|
||||
#else
|
||||
void editCountInc() { ++s_editCntGbl; }
|
||||
@@ -1957,6 +2140,10 @@ public:
|
||||
AstNodeDType* findBasicDType(VBasicDTypeKwd kwd) const;
|
||||
static AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
|
||||
|
||||
static VCastable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp,
|
||||
const AstNode* fromConstp);
|
||||
static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2);
|
||||
|
||||
// METHODS - dump and error
|
||||
void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex);
|
||||
void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN
|
||||
@@ -1998,7 +2185,9 @@ public:
|
||||
AstNode* belowp); // When calling, "this" is second argument
|
||||
|
||||
// METHODS - Iterate on a tree
|
||||
AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep
|
||||
AstNode* cloneTree(bool cloneNextLink,
|
||||
bool needPure = false); // Not const, as sets clonep() on original nodep
|
||||
AstNode* cloneTreePure(bool cloneNextLink) { return cloneTree(cloneNextLink, true); }
|
||||
bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable?
|
||||
inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p?
|
||||
// Does tree of this == node2p?, not allowing non-isGateOptimizable
|
||||
@@ -2023,7 +2212,14 @@ public:
|
||||
void dumpTreeDot(std::ostream& os = std::cout) const;
|
||||
void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true);
|
||||
|
||||
bool isTreePureRecurse() const;
|
||||
// METHODS - static advancement
|
||||
static AstNode* afterCommentp(AstNode* nodep) {
|
||||
// Skip over comments starting at provided nodep,
|
||||
// such as to determine if a AstIf is empty.
|
||||
// nodep may be null, if so return nullptr.
|
||||
while (nodep && VN_IS(nodep, Comment)) nodep = nodep->nextp();
|
||||
return nodep;
|
||||
}
|
||||
|
||||
// METHODS - queries
|
||||
// Changes control flow, disable some optimizations
|
||||
@@ -2033,11 +2229,13 @@ public:
|
||||
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
|
||||
virtual bool isGateDedupable() const { return isGateOptimizable(); }
|
||||
// Else creates output or exits, etc, not unconsumed
|
||||
virtual bool isOutputter() const { return false; }
|
||||
virtual bool isOutputter() { return false; }
|
||||
// Else a AstTime etc which output can't be predicted from input
|
||||
virtual bool isPredictOptimizable() const { return !isTimingControl(); }
|
||||
// Else a $display, etc, that must be ordered with other displays
|
||||
virtual bool isPure() const { return true; }
|
||||
virtual bool isPure() { return true; }
|
||||
// Iff isPure on current node and any nextp()
|
||||
bool isPureAndNext() { return isPure() && (!nextp() || nextp()->isPure()); }
|
||||
// Else a AstTime etc that can't be substituted out
|
||||
virtual bool isSubstOptimizable() const { return true; }
|
||||
// An event control, delay, wait, etc.
|
||||
@@ -2046,7 +2244,10 @@ public:
|
||||
// statement is unlikely to be taken
|
||||
virtual bool isUnlikely() const { return false; }
|
||||
virtual int instrCount() const { return 0; }
|
||||
virtual bool same(const AstNode*) const { return true; }
|
||||
// Iff node is identical to anouther node
|
||||
virtual bool isSame(const AstNode* samep) const {
|
||||
return type() == samep->type() && same(samep);
|
||||
}
|
||||
// Iff has a data type; dtype() must be non null
|
||||
virtual bool hasDType() const VL_MT_SAFE { return false; }
|
||||
// Iff has a non-null childDTypep(), as generic node function
|
||||
|
||||
@@ -39,6 +39,10 @@ bool AstNode::isDouble() const VL_MT_STABLE {
|
||||
bool AstNode::isString() const VL_MT_STABLE {
|
||||
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString();
|
||||
}
|
||||
bool AstNode::isEvent() const VL_MT_STABLE {
|
||||
return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isEvent();
|
||||
}
|
||||
|
||||
bool AstNode::isSigned() const VL_MT_STABLE { return dtypep() && dtypep()->isSigned(); }
|
||||
|
||||
bool AstNode::isClassHandleValue() const {
|
||||
|
||||
+73
-25
@@ -160,14 +160,14 @@ public:
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
const AstNodeArrayDType* const asamep = VN_DBG_AS(samep, NodeArrayDType);
|
||||
return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep()
|
||||
&& rangenp()->sameTree(asamep->rangenp()));
|
||||
} // HashedDT doesn't recurse, so need to check children
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
return (asamep && type() == samep->type() && hi() == asamep->hi()
|
||||
&& rangenp()->sameTree(asamep->rangenp())
|
||||
if (type() != samep->type()) return false;
|
||||
const AstNodeArrayDType* const asamep = VN_DBG_AS(samep, NodeArrayDType);
|
||||
return (hi() == asamep->hi() && rangenp()->sameTree(asamep->rangenp())
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()));
|
||||
}
|
||||
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
|
||||
@@ -314,14 +314,15 @@ public:
|
||||
if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep();
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
const AstAssocArrayDType* const asamep = VN_DBG_AS(samep, AssocArrayDType);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
if (!asamep->keyDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep());
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
return type() == samep->type() && asamep->subDTypep()
|
||||
if (type() != samep->type()) return false;
|
||||
const AstAssocArrayDType* const asamep = VN_DBG_AS(samep, AssocArrayDType);
|
||||
return asamep->subDTypep()
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||
}
|
||||
string prettyDTypeName() const override;
|
||||
@@ -494,6 +495,41 @@ public:
|
||||
int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); }
|
||||
bool isCompound() const override { return true; }
|
||||
};
|
||||
class AstCDType final : public AstNodeDType {
|
||||
// Raw "C" data type passed directly to output
|
||||
string m_name; // Name of data type, printed when do V3EmitC
|
||||
public:
|
||||
AstCDType(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_CDType(fl)
|
||||
, m_name{name} {
|
||||
this->dtypep(this);
|
||||
}
|
||||
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstCDType;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstCDType* const asamep = VN_DBG_AS(samep, CDType);
|
||||
return m_name == asamep->m_name;
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return same(samep); }
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
string prettyDTypeName() const override { return m_name; }
|
||||
const char* broken() const override { return nullptr; }
|
||||
// METHODS
|
||||
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
|
||||
AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
|
||||
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
int widthAlignBytes() const override { return 8; } // Assume
|
||||
int widthTotalBytes() const override { return 8; } // Assume
|
||||
bool isCompound() const override { return true; }
|
||||
static string typeToHold(uint64_t maxItem) {
|
||||
return (maxItem < (1ULL << 8)) ? "CData"
|
||||
: (maxItem < (1ULL << 16)) ? "SData"
|
||||
: (maxItem < (1ULL << 32)) ? "IData"
|
||||
: "QData";
|
||||
}
|
||||
};
|
||||
class AstClassRefDType final : public AstNodeDType {
|
||||
// Reference to a class
|
||||
// @astgen op1 := paramsp: List[AstPin]
|
||||
@@ -512,7 +548,7 @@ public:
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstClassRefDType* const asamep = static_cast<const AstClassRefDType*>(samep);
|
||||
const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType);
|
||||
return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep);
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
@@ -561,7 +597,7 @@ public:
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstConstDType* const sp = static_cast<const AstConstDType*>(samep);
|
||||
const AstConstDType* const sp = VN_DBG_AS(samep, ConstDType);
|
||||
return (m_refDTypep == sp->m_refDTypep);
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
@@ -610,7 +646,7 @@ public:
|
||||
ASTGEN_MEMBERS_AstDefImplicitDType;
|
||||
int uniqueNum() const { return m_uniqueNum; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstDefImplicitDType* const sp = static_cast<const AstDefImplicitDType*>(samep);
|
||||
const AstDefImplicitDType* const sp = VN_DBG_AS(samep, DefImplicitDType);
|
||||
return uniqueNum() == sp->uniqueNum();
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
@@ -661,13 +697,14 @@ public:
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
const AstDynArrayDType* const asamep = VN_DBG_AS(samep, DynArrayDType);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return subDTypep() == asamep->subDTypep();
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
return type() == samep->type() && asamep->subDTypep()
|
||||
if (type() != samep->type()) return false;
|
||||
const AstDynArrayDType* const asamep = VN_DBG_AS(samep, DynArrayDType);
|
||||
return asamep->subDTypep()
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||
}
|
||||
string prettyDTypeName() const override;
|
||||
@@ -719,10 +756,14 @@ class AstEnumDType final : public AstNodeDType {
|
||||
// Parents: TYPEDEF/MODULE
|
||||
// @astgen op1 := childDTypep : Optional[AstNodeDType]
|
||||
// @astgen op2 := itemsp : List[AstEnumItem]
|
||||
public:
|
||||
using TableMap = std::map<VAttrType, AstVar*>;
|
||||
|
||||
private:
|
||||
string m_name; // Name from upper typedef, if any
|
||||
AstNodeDType* m_refDTypep = nullptr; // Elements are of this type after V3Width
|
||||
const int m_uniqueNum = 0;
|
||||
TableMap m_tableMap; // Created table for V3Width only to remove duplicates
|
||||
|
||||
public:
|
||||
AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstEnumItem* itemsp)
|
||||
@@ -735,9 +776,12 @@ public:
|
||||
widthFromSub(subDTypep());
|
||||
}
|
||||
ASTGEN_MEMBERS_AstEnumDType;
|
||||
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep())));
|
||||
BROKEN_RTN(std::any_of(m_tableMap.begin(), m_tableMap.end(),
|
||||
[](const auto& p) { return !p.second->brokeExists(); }));
|
||||
return nullptr;
|
||||
}
|
||||
void cloneRelink() override {
|
||||
@@ -745,7 +789,7 @@ public:
|
||||
}
|
||||
int uniqueNum() const { return m_uniqueNum; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstEnumDType* const sp = static_cast<const AstEnumDType*>(samep);
|
||||
const AstEnumDType* const sp = VN_DBG_AS(samep, EnumDType);
|
||||
return uniqueNum() == sp->uniqueNum();
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
|
||||
@@ -774,6 +818,8 @@ public:
|
||||
return count;
|
||||
}
|
||||
bool isCompound() const override { return false; }
|
||||
TableMap& tableMap() { return m_tableMap; }
|
||||
const TableMap& tableMap() const { return m_tableMap; }
|
||||
};
|
||||
class AstIfaceRefDType final : public AstNodeDType {
|
||||
// Reference to an interface, either for a port, or inside parent cell
|
||||
@@ -938,9 +984,9 @@ public:
|
||||
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
|
||||
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
const AstParamTypeDType* const sp = static_cast<const AstParamTypeDType*>(samep);
|
||||
return type() == samep->type() && sp
|
||||
&& this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp());
|
||||
if (type() != samep->type()) return false;
|
||||
const AstParamTypeDType* const sp = VN_DBG_AS(samep, ParamTypeDType);
|
||||
return this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp());
|
||||
}
|
||||
int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); }
|
||||
int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); }
|
||||
@@ -1011,13 +1057,14 @@ public:
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstQueueDType* const asamep = static_cast<const AstQueueDType*>(samep);
|
||||
const AstQueueDType* const asamep = VN_DBG_AS(samep, QueueDType);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep());
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
const AstQueueDType* const asamep = static_cast<const AstQueueDType*>(samep);
|
||||
return type() == samep->type() && asamep->subDTypep()
|
||||
if (type() != samep->type()) return false;
|
||||
const AstQueueDType* const asamep = VN_DBG_AS(samep, QueueDType);
|
||||
return asamep->subDTypep()
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||
}
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
@@ -1075,7 +1122,7 @@ public:
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstRefDType* const asamep = static_cast<const AstRefDType*>(samep);
|
||||
const AstRefDType* const asamep = VN_DBG_AS(samep, RefDType);
|
||||
return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep
|
||||
&& m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep);
|
||||
}
|
||||
@@ -1153,13 +1200,14 @@ public:
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
const AstSampleQueueDType* const asamep = VN_DBG_AS(samep, SampleQueueDType);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep());
|
||||
}
|
||||
bool similarDType(const AstNodeDType* samep) const override {
|
||||
const AstSampleQueueDType* const asamep = static_cast<const AstSampleQueueDType*>(samep);
|
||||
return type() == samep->type() && asamep->subDTypep()
|
||||
if (type() != samep->type()) return false;
|
||||
const AstSampleQueueDType* const asamep = VN_DBG_AS(samep, SampleQueueDType);
|
||||
return asamep->subDTypep()
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||
}
|
||||
void dumpSmall(std::ostream& str) const override;
|
||||
@@ -1352,7 +1400,7 @@ public:
|
||||
ASTGEN_MEMBERS_AstUnpackArrayDType;
|
||||
string prettyDTypeName() const override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstUnpackArrayDType* const sp = static_cast<const AstUnpackArrayDType*>(samep);
|
||||
const AstUnpackArrayDType* const sp = VN_DBG_AS(samep, UnpackArrayDType);
|
||||
return m_isCompound == sp->m_isCompound;
|
||||
}
|
||||
// Outer dimension comes first. The first element is this node.
|
||||
|
||||
+206
-69
@@ -69,6 +69,8 @@ class AstNodeBiop VL_NOT_FINAL : public AstNodeExpr {
|
||||
// Binary expression
|
||||
// @astgen op1 := lhsp : AstNodeExpr
|
||||
// @astgen op2 := rhsp : AstNodeExpr
|
||||
VIsCached m_purity; // Pure state
|
||||
|
||||
protected:
|
||||
AstNodeBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: AstNodeExpr{t, fl} {
|
||||
@@ -93,6 +95,11 @@ public:
|
||||
virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors?
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode*) const override { return true; }
|
||||
bool isPure() override;
|
||||
const char* broken() const override;
|
||||
|
||||
private:
|
||||
bool getPurityRecurse() const { return lhsp()->isPure() && rhsp()->isPure(); }
|
||||
};
|
||||
class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop {
|
||||
// Binary expr with commutative properties
|
||||
@@ -176,6 +183,7 @@ class AstNodeCCall VL_NOT_FINAL : public AstNodeExpr {
|
||||
// @astgen op2 := argsp : List[AstNodeExpr] // Note: op1 used by some sub-types only
|
||||
AstCFunc* m_funcp;
|
||||
string m_argTypes;
|
||||
bool m_superReference = false; // Called with super reference
|
||||
|
||||
protected:
|
||||
AstNodeCCall(VNType t, FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr)
|
||||
@@ -191,13 +199,13 @@ public:
|
||||
const char* broken() const override;
|
||||
int instrCount() const override { return INSTR_COUNT_CALL; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstNodeCCall* const asamep = static_cast<const AstNodeCCall*>(samep);
|
||||
const AstNodeCCall* const asamep = VN_DBG_AS(samep, NodeCCall);
|
||||
return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes());
|
||||
}
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override;
|
||||
bool isOutputter() const override { return !isPure(); }
|
||||
bool isPure() override;
|
||||
bool isOutputter() override { return !isPure(); }
|
||||
AstCFunc* funcp() const { return m_funcp; }
|
||||
void funcp(AstCFunc* funcp) { m_funcp = funcp; }
|
||||
void argTypes(const string& str) { m_argTypes = str; }
|
||||
@@ -206,6 +214,8 @@ public:
|
||||
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const final override { return true; }
|
||||
bool superReference() const { return m_superReference; }
|
||||
void superReference(bool flag) { m_superReference = flag; }
|
||||
};
|
||||
class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr {
|
||||
// A reference to a task (or function)
|
||||
@@ -219,6 +229,8 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr {
|
||||
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||
bool m_pli = false; // Pli system call ($name)
|
||||
VIsCached m_purity; // Pure state
|
||||
|
||||
protected:
|
||||
AstNodeFTaskRef(VNType t, FileLine* fl, AstNode* namep, AstNodeExpr* pinsp)
|
||||
: AstNodeExpr{t, fl} {
|
||||
@@ -249,11 +261,14 @@ public:
|
||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||
bool pli() const { return m_pli; }
|
||||
void pli(bool flag) { m_pli = flag; }
|
||||
bool isPure() const override;
|
||||
bool isPure() override;
|
||||
|
||||
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
|
||||
|
||||
private:
|
||||
bool getPurityRecurse() const;
|
||||
};
|
||||
class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr {
|
||||
// Something that becomes an AstSel
|
||||
@@ -261,6 +276,8 @@ class AstNodePreSel VL_NOT_FINAL : public AstNodeExpr {
|
||||
// @astgen op2 := rhsp : AstNodeExpr
|
||||
// @astgen op3 := thsp : Optional[AstNodeExpr]
|
||||
// @astgen op4 := attrp : Optional[AstAttrOf]
|
||||
VIsCached m_purity; // Pure state
|
||||
|
||||
protected:
|
||||
AstNodePreSel(VNType t, FileLine* fl, AstNodeExpr* fromp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
|
||||
: AstNodeExpr{t, fl} {
|
||||
@@ -277,6 +294,13 @@ public:
|
||||
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const final override { V3ERROR_NA_RETURN(true); }
|
||||
bool isPure() override;
|
||||
const char* broken() const override;
|
||||
|
||||
private:
|
||||
bool getPurityRecurse() const {
|
||||
return fromp()->isPure() && rhsp()->isPure() && (!thsp() || thsp()->isPure());
|
||||
}
|
||||
};
|
||||
class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr {
|
||||
// 4-ary expression
|
||||
@@ -284,6 +308,8 @@ class AstNodeQuadop VL_NOT_FINAL : public AstNodeExpr {
|
||||
// @astgen op2 := rhsp : AstNodeExpr
|
||||
// @astgen op3 := thsp : AstNodeExpr
|
||||
// @astgen op4 := fhsp : AstNodeExpr
|
||||
VIsCached m_purity; // Pure state
|
||||
|
||||
protected:
|
||||
AstNodeQuadop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp,
|
||||
AstNodeExpr* fhsp)
|
||||
@@ -311,6 +337,13 @@ public:
|
||||
virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode*) const override { return true; }
|
||||
bool isPure() override;
|
||||
const char* broken() const override;
|
||||
|
||||
private:
|
||||
bool getPurityRecurse() const {
|
||||
return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure() && fhsp()->isPure();
|
||||
}
|
||||
};
|
||||
class AstNodeTermop VL_NOT_FINAL : public AstNodeExpr {
|
||||
// Terminal operator -- an operator with no "inputs"
|
||||
@@ -330,6 +363,8 @@ class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr {
|
||||
// @astgen op1 := lhsp : AstNodeExpr
|
||||
// @astgen op2 := rhsp : AstNodeExpr
|
||||
// @astgen op3 := thsp : AstNodeExpr
|
||||
VIsCached m_purity; // Pure state
|
||||
|
||||
protected:
|
||||
AstNodeTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, AstNodeExpr* thsp)
|
||||
: AstNodeExpr{t, fl} {
|
||||
@@ -354,6 +389,13 @@ public:
|
||||
virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode*) const override { return true; }
|
||||
bool isPure() override;
|
||||
const char* broken() const override;
|
||||
|
||||
private:
|
||||
bool getPurityRecurse() const {
|
||||
return lhsp()->isPure() && rhsp()->isPure() && thsp()->isPure();
|
||||
}
|
||||
};
|
||||
class AstNodeCond VL_NOT_FINAL : public AstNodeTriop {
|
||||
// @astgen alias op1 := condp
|
||||
@@ -403,6 +445,8 @@ public:
|
||||
class AstNodeUniop VL_NOT_FINAL : public AstNodeExpr {
|
||||
// Unary expression
|
||||
// @astgen op1 := lhsp : AstNodeExpr
|
||||
VIsCached m_purity; // Pure state
|
||||
|
||||
protected:
|
||||
AstNodeUniop(VNType t, FileLine* fl, AstNodeExpr* lhsp)
|
||||
: AstNodeExpr{t, fl} {
|
||||
@@ -424,6 +468,8 @@ public:
|
||||
virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors?
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode*) const override { return true; }
|
||||
bool isPure() override;
|
||||
const char* broken() const override;
|
||||
};
|
||||
class AstNodeSystemUniopD VL_NOT_FINAL : public AstNodeUniop {
|
||||
public:
|
||||
@@ -574,6 +620,7 @@ public:
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
bool isPure() override { return pure(); }
|
||||
bool pure() const { return m_pure; }
|
||||
void pure(bool flag) { m_pure = flag; }
|
||||
};
|
||||
@@ -597,10 +644,10 @@ public:
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstCMethodHard* asamep = static_cast<const AstCMethodHard*>(samep);
|
||||
const AstCMethodHard* const asamep = VN_DBG_AS(samep, CMethodHard);
|
||||
return (m_name == asamep->m_name);
|
||||
}
|
||||
bool isPure() const override { return m_pure; }
|
||||
bool isPure() override { return m_pure; }
|
||||
int instrCount() const override;
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -729,7 +776,7 @@ public:
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
return (m_classOrPackageNodep
|
||||
== static_cast<const AstClassOrPackageRef*>(samep)->m_classOrPackageNodep);
|
||||
== VN_DBG_AS(samep, ClassOrPackageRef)->m_classOrPackageNodep);
|
||||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
@@ -1000,9 +1047,14 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstConst* const sp = static_cast<const AstConst*>(samep);
|
||||
const AstConst* const sp = VN_DBG_AS(samep, Const);
|
||||
return num().isCaseEq(sp->num());
|
||||
}
|
||||
void cloneRelink() override { m_num.nodep(this); }
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(m_num.nodep() && m_num.nodep() != this);
|
||||
return nullptr;
|
||||
}
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool isEqAllOnes() const { return num().isEqAllOnes(width()); }
|
||||
bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); }
|
||||
@@ -1089,11 +1141,9 @@ public:
|
||||
string name() const override VL_MT_STABLE { return itemp()->name(); }
|
||||
int instrCount() const override { return 0; }
|
||||
const char* broken() const override;
|
||||
void cloneRelink() override {
|
||||
if (m_itemp->clonep()) m_itemp = m_itemp->clonep();
|
||||
}
|
||||
void cloneRelink() override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstEnumItemRef* const sp = static_cast<const AstEnumItemRef*>(samep);
|
||||
const AstEnumItemRef* const sp = VN_DBG_AS(samep, EnumItemRef);
|
||||
return itemp() == sp->itemp();
|
||||
}
|
||||
AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; }
|
||||
@@ -1121,7 +1171,10 @@ public:
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isPure() override {
|
||||
if (AstNode::afterCommentp(stmtsp())) return false;
|
||||
return resultp()->isPure();
|
||||
}
|
||||
bool same(const AstNode*) const override { return true; }
|
||||
};
|
||||
class AstFError final : public AstNodeExpr {
|
||||
@@ -1139,7 +1192,7 @@ public:
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs() * 64; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstFOpen final : public AstNodeExpr {
|
||||
@@ -1158,8 +1211,8 @@ public:
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -1177,8 +1230,8 @@ public:
|
||||
string verilogKwd() const override { return "$fopen"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -1201,8 +1254,8 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering
|
||||
bool isOutputter() const override { return true; } // SPECIAL: makes output
|
||||
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
|
||||
bool isOutputter() override { return true; } // SPECIAL: makes output
|
||||
bool cleanOut() const override { return false; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -1219,8 +1272,8 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
@@ -1244,11 +1297,11 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering
|
||||
bool isOutputter() const override { return true; } // SPECIAL: makes output
|
||||
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
|
||||
bool isOutputter() override { return true; } // SPECIAL: makes output
|
||||
bool cleanOut() const override { return false; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return text() == static_cast<const AstFScanF*>(samep)->text();
|
||||
return text() == VN_DBG_AS(samep, FScanF)->text();
|
||||
}
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
void text(const string& text) { m_text = text; }
|
||||
@@ -1270,8 +1323,8 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering
|
||||
bool isOutputter() const override { return true; } // SPECIAL: makes output
|
||||
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
|
||||
bool isOutputter() override { return true; } // SPECIAL: makes output
|
||||
bool cleanOut() const override { return false; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -1288,8 +1341,8 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
@@ -1377,7 +1430,7 @@ public:
|
||||
bool same(const AstNode* samep) const override {
|
||||
// Only works if exact same children, instead should override comparison
|
||||
// of children list, and instead use map-vs-map key/value compare
|
||||
return m_map == static_cast<const AstInitArray*>(samep)->m_map;
|
||||
return m_map == VN_DBG_AS(samep, InitArray)->m_map;
|
||||
}
|
||||
void addValuep(AstNodeExpr* newp) { addIndexValuep(m_map.size(), newp); }
|
||||
const KeyItemMap& map() const { return m_map; }
|
||||
@@ -1533,7 +1586,7 @@ public:
|
||||
void dump(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstParseRef* const asamep = static_cast<const AstParseRef*>(samep);
|
||||
const AstParseRef* const asamep = VN_DBG_AS(samep, ParseRef);
|
||||
return (expect() == asamep->expect() && m_name == asamep->m_name);
|
||||
}
|
||||
void name(const string& name) override { m_name = name; }
|
||||
@@ -1728,7 +1781,7 @@ public:
|
||||
string name() const override VL_MT_STABLE { return m_text; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return text() == static_cast<const AstSFormatF*>(samep)->text();
|
||||
return text() == VN_DBG_AS(samep, SFormatF)->text();
|
||||
}
|
||||
string verilogKwd() const override { return "$sformatf"; }
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
@@ -1766,11 +1819,11 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering
|
||||
bool isOutputter() const override { return true; } // SPECIAL: makes output
|
||||
bool isPure() override { return false; } // SPECIAL: has 'visual' ordering
|
||||
bool isOutputter() override { return true; } // SPECIAL: makes output
|
||||
bool cleanOut() const override { return false; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return text() == static_cast<const AstSScanF*>(samep)->text();
|
||||
return text() == VN_DBG_AS(samep, SScanF)->text();
|
||||
}
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
void text(const string& text) { m_text = text; }
|
||||
@@ -1810,8 +1863,8 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstScopeName;
|
||||
bool same(const AstNode* samep) const override {
|
||||
return (m_dpiExport == static_cast<const AstScopeName*>(samep)->m_dpiExport
|
||||
&& m_forFormat == static_cast<const AstScopeName*>(samep)->m_forFormat);
|
||||
const AstScopeName* const sp = VN_DBG_AS(samep, ScopeName);
|
||||
return (m_dpiExport == sp->m_dpiExport && m_forFormat == sp->m_forFormat);
|
||||
}
|
||||
string emitVerilog() override { return ""; }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -1924,8 +1977,8 @@ public:
|
||||
string emitC() override { return "VL_STACKTRACE_N()"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
@@ -1954,7 +2007,7 @@ public:
|
||||
return VN_IS(fromp()->dtypep()->skipRefp(), StructDType);
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstStructSel* const sp = static_cast<const AstStructSel*>(samep);
|
||||
const AstStructSel* const sp = VN_DBG_AS(samep, StructSel);
|
||||
return m_name == sp->m_name;
|
||||
}
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
@@ -1970,8 +2023,8 @@ public:
|
||||
string verilogKwd() const override { return "$ignored"; }
|
||||
bool isGateOptimizable() const override { return false; } // Though deleted before opt
|
||||
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
|
||||
bool isPure() const override { return false; } // Though deleted before opt
|
||||
bool isOutputter() const override { return true; } // Though deleted before opt
|
||||
bool isPure() override { return false; } // Though deleted before opt
|
||||
bool isOutputter() override { return true; } // Though deleted before opt
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
@@ -1992,8 +2045,8 @@ public:
|
||||
string emitC() override { return "VL_SYSTEM_%nq(%lw, %P)"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
@@ -2076,8 +2129,8 @@ public:
|
||||
bool cleanOut() const override { return false; }
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() override { return true; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isSubstOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
@@ -2132,7 +2185,7 @@ public:
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return !outp(); }
|
||||
bool isPure() override { return !outp(); }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -2239,7 +2292,7 @@ public:
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() * 20; }
|
||||
bool isPure() const override { return true; }
|
||||
bool isPure() override { return true; }
|
||||
};
|
||||
class AstCompareNN final : public AstNodeBiop {
|
||||
// Verilog str.compare() and str.icompare()
|
||||
@@ -2463,7 +2516,7 @@ public:
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() * 64; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
AstNode* charp() const { return rhsp(); }
|
||||
};
|
||||
@@ -2748,11 +2801,6 @@ public:
|
||||
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
|
||||
};
|
||||
class AstLogOr final : public AstNodeBiop {
|
||||
// LOGOR with optional side effects
|
||||
// Side effects currently used in some V3Width code
|
||||
// TBD if this concept is generally adopted for side-effect tracking
|
||||
// versus V3Const tracking it itself
|
||||
bool m_sideEffect = false; // Has side effect, relies on short-circuiting
|
||||
public:
|
||||
AstLogOr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
: ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) {
|
||||
@@ -2765,11 +2813,6 @@ public:
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opLogOr(lhs, rhs);
|
||||
}
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstLogOr* const sp = static_cast<const AstLogOr*>(samep);
|
||||
return m_sideEffect == sp->m_sideEffect;
|
||||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
string emitVerilog() override { return "%k(%l %f|| %r)"; }
|
||||
string emitC() override { return "VL_LOGOR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return "||"; }
|
||||
@@ -2779,9 +2822,6 @@ public:
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() + INSTR_COUNT_BRANCH; }
|
||||
bool isPure() const override { return !m_sideEffect; }
|
||||
void sideEffect(bool flag) { m_sideEffect = flag; }
|
||||
bool sideEffect() const { return m_sideEffect; }
|
||||
};
|
||||
class AstLt final : public AstNodeBiop {
|
||||
public:
|
||||
@@ -3236,6 +3276,30 @@ public:
|
||||
bool sizeMattersLhs() const override { return true; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
};
|
||||
class AstShiftLOvr final : public AstNodeBiop {
|
||||
// Like ShiftL but checks for an over shift and returns zeros
|
||||
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftL
|
||||
public:
|
||||
AstShiftLOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER_ShiftLOvr(fl, lhsp, rhsp) {
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstShiftLOvr;
|
||||
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstShiftLOvr{fileline(), lhsp, rhsp};
|
||||
}
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opShiftL(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f<< %r)"; }
|
||||
string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override { return false; }
|
||||
bool cleanRhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return true; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
};
|
||||
class AstShiftR final : public AstNodeBiop {
|
||||
public:
|
||||
AstShiftR(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
|
||||
@@ -3261,6 +3325,31 @@ public:
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
};
|
||||
class AstShiftROvr final : public AstNodeBiop {
|
||||
// Like ShiftR but checks for an over shift and returns zeros
|
||||
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftR
|
||||
public:
|
||||
AstShiftROvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER_ShiftROvr(fl, lhsp, rhsp) {
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstShiftROvr;
|
||||
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstShiftROvr{fileline(), lhsp, rhsp};
|
||||
}
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opShiftR(lhs, rhs);
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f>> %r)"; }
|
||||
string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool cleanRhs() const override { return true; }
|
||||
// LHS size might be > output size, so don't want to force size
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
};
|
||||
class AstShiftRS final : public AstNodeBiop {
|
||||
// Shift right with sign extension, >>> operator
|
||||
// Output data type's width determines which bit is used for sign extension
|
||||
@@ -3287,6 +3376,33 @@ public:
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
bool signedFlavor() const override { return true; }
|
||||
};
|
||||
class AstShiftRSOvr final : public AstNodeBiop {
|
||||
// Shift right with sign extension, >>> operator, checks for an over shift and returns zeros
|
||||
// Output data type's width determines which bit is used for sign extension
|
||||
// TODO: All Verilog shifts should start as these and later get demoted to AstShiftRSOvr
|
||||
public:
|
||||
AstShiftRSOvr(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER_ShiftRSOvr(fl, lhsp, rhsp) {
|
||||
// Important that widthMin be correct, as opExtend requires it after V3Expand
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstShiftRSOvr;
|
||||
AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override {
|
||||
return new AstShiftRSOvr{fileline(), lhsp, rhsp};
|
||||
}
|
||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||
out.opShiftRS(lhs, rhs, lhsp()->widthMinV());
|
||||
}
|
||||
string emitVerilog() override { return "%k(%l %f>>> %r)"; }
|
||||
string emitC() override { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
string emitSimpleOperator() override { return ""; }
|
||||
bool cleanOut() const override { return false; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool cleanRhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
bool sizeMattersRhs() const override { return false; }
|
||||
bool signedFlavor() const override { return true; }
|
||||
};
|
||||
class AstSub final : public AstNodeBiop {
|
||||
public:
|
||||
AstSub(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
|
||||
@@ -4085,12 +4201,15 @@ public:
|
||||
// === AstNodeFTaskRef ===
|
||||
class AstFuncRef final : public AstNodeFTaskRef {
|
||||
// A reference to a function
|
||||
bool m_superReference = false; // Called with super reference
|
||||
public:
|
||||
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNodeExpr* pinsp)
|
||||
: ASTGEN_SUPER_FuncRef(fl, (AstNode*)namep, pinsp) {}
|
||||
AstFuncRef(FileLine* fl, const string& name, AstNodeExpr* pinsp)
|
||||
: ASTGEN_SUPER_FuncRef(fl, name, pinsp) {}
|
||||
ASTGEN_MEMBERS_AstFuncRef;
|
||||
bool superReference() const { return m_superReference; }
|
||||
void superReference(bool flag) { m_superReference = flag; }
|
||||
};
|
||||
class AstMethodCall final : public AstNodeFTaskRef {
|
||||
// A reference to a member task (or function)
|
||||
@@ -4127,6 +4246,7 @@ public:
|
||||
};
|
||||
class AstTaskRef final : public AstNodeFTaskRef {
|
||||
// A reference to a task
|
||||
bool m_superReference = false; // Called with super reference
|
||||
public:
|
||||
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNodeExpr* pinsp)
|
||||
: ASTGEN_SUPER_TaskRef(fl, (AstNode*)namep, pinsp) {
|
||||
@@ -4137,6 +4257,8 @@ public:
|
||||
dtypeSetVoid();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstTaskRef;
|
||||
bool superReference() const { return m_superReference; }
|
||||
void superReference(bool flag) { m_superReference = flag; }
|
||||
};
|
||||
|
||||
// === AstNodePreSel ===
|
||||
@@ -4187,10 +4309,10 @@ class AstCountBits final : public AstNodeQuadop {
|
||||
// Number of bits set in vector
|
||||
public:
|
||||
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p)
|
||||
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false),
|
||||
ctrl1p->cloneTree(false)) {}
|
||||
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTreePure(false),
|
||||
ctrl1p->cloneTreePure(false)) {}
|
||||
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p)
|
||||
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {}
|
||||
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTreePure(false)) {}
|
||||
AstCountBits(FileLine* fl, AstNodeExpr* exprp, AstNodeExpr* ctrl1p, AstNodeExpr* ctrl2p,
|
||||
AstNodeExpr* ctrl3p)
|
||||
: ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {}
|
||||
@@ -4637,7 +4759,7 @@ public:
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast
|
||||
bool same(const AstNode* samep) const override {
|
||||
return size() == static_cast<const AstCCast*>(samep)->size();
|
||||
return size() == VN_DBG_AS(samep, CCast)->size();
|
||||
}
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
//
|
||||
@@ -4760,7 +4882,7 @@ public:
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() * 16; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
};
|
||||
class AstFGetC final : public AstNodeUniop {
|
||||
@@ -4777,7 +4899,7 @@ public:
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
int instrCount() const override { return widthInstrs() * 64; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
};
|
||||
class AstISToRD final : public AstNodeUniop {
|
||||
@@ -5083,6 +5205,21 @@ public:
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
int instrCount() const override { return 1 + V3Number::log2b(width()); }
|
||||
};
|
||||
class AstResizeLValue final : public AstNodeUniop {
|
||||
// Resize a LValue into a wider/narrower entity at function argument boundry
|
||||
// Width and signness is implied from nodep->width()
|
||||
public:
|
||||
AstResizeLValue(FileLine* fl, AstNodeExpr* lhsp)
|
||||
: ASTGEN_SUPER_ResizeLValue(fl, lhsp) {}
|
||||
ASTGEN_MEMBERS_AstResizeLValue;
|
||||
void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; }
|
||||
string emitVerilog() override { return "%l"; }
|
||||
string emitC() final override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool cleanLhs() const override { return true; }
|
||||
bool sizeMattersLhs() const override { return false; }
|
||||
int instrCount() const override { return 0; }
|
||||
};
|
||||
class AstSigned final : public AstNodeUniop {
|
||||
// $signed(lhs)
|
||||
public:
|
||||
@@ -5416,7 +5553,7 @@ public:
|
||||
bool cleanOut() const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstVarXRef* asamep = static_cast<const AstVarXRef*>(samep);
|
||||
const AstVarXRef* asamep = VN_DBG_AS(samep, VarXRef);
|
||||
return (selfPointer() == asamep->selfPointer() && varp() == asamep->varp()
|
||||
&& name() == asamep->name() && dotted() == asamep->dotted());
|
||||
}
|
||||
|
||||
+137
-105
@@ -84,10 +84,13 @@ private:
|
||||
bool m_dpiPure : 1; // DPI import pure (vs. virtual pure)
|
||||
bool m_pureVirtual : 1; // Pure virtual
|
||||
bool m_recursive : 1; // Recursive or part of recursion
|
||||
bool m_static : 1; // Static method in class
|
||||
bool m_underGenerate : 1; // Under generate (for warning)
|
||||
bool m_virtual : 1; // Virtual method in class
|
||||
bool m_needProcess : 1; // Implements part of a process that allocates std::process
|
||||
VLifetime m_lifetime; // Lifetime
|
||||
bool m_needProcess : 1; // Needs access to VlProcess of the caller
|
||||
VLifetime m_lifetime; // Default lifetime of local vars
|
||||
VIsCached m_purity; // Pure state
|
||||
|
||||
protected:
|
||||
AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp)
|
||||
: AstNode{t, fl}
|
||||
@@ -110,6 +113,7 @@ protected:
|
||||
, m_dpiPure{false}
|
||||
, m_pureVirtual{false}
|
||||
, m_recursive{false}
|
||||
, m_static{false}
|
||||
, m_underGenerate{false}
|
||||
, m_virtual{false}
|
||||
, m_needProcess{false} {
|
||||
@@ -171,6 +175,8 @@ public:
|
||||
bool pureVirtual() const { return m_pureVirtual; }
|
||||
void recursive(bool flag) { m_recursive = flag; }
|
||||
bool recursive() const { return m_recursive; }
|
||||
void isStatic(bool flag) { m_static = flag; }
|
||||
bool isStatic() const { return m_static; }
|
||||
void underGenerate(bool flag) { m_underGenerate = flag; }
|
||||
bool underGenerate() const { return m_underGenerate; }
|
||||
void isVirtual(bool flag) { m_virtual = flag; }
|
||||
@@ -180,6 +186,8 @@ public:
|
||||
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
|
||||
VLifetime lifetime() const { return m_lifetime; }
|
||||
bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); }
|
||||
bool isPure() override;
|
||||
const char* broken() const override;
|
||||
void propagateAttrFrom(const AstNodeFTask* fromp) {
|
||||
// Creating a wrapper with e.g. cloneType(); preserve some attributes
|
||||
classMethod(fromp->classMethod());
|
||||
@@ -189,6 +197,9 @@ public:
|
||||
lifetime(fromp->lifetime());
|
||||
underGenerate(fromp->underGenerate());
|
||||
}
|
||||
|
||||
private:
|
||||
bool getPurityRecurse() const;
|
||||
};
|
||||
class AstNodeFile VL_NOT_FINAL : public AstNode {
|
||||
// Emitted Output file
|
||||
@@ -227,6 +238,7 @@ private:
|
||||
bool m_inLibrary : 1; // From a library, no error if not used, never top level
|
||||
bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors
|
||||
bool m_hasGParam : 1; // Has global parameter (for link)
|
||||
bool m_hasParameterList : 1; // Has #() for parameter declaration
|
||||
bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma
|
||||
bool m_internal : 1; // Internally created
|
||||
bool m_recursive : 1; // Recursive module
|
||||
@@ -241,6 +253,7 @@ protected:
|
||||
, m_inLibrary{false}
|
||||
, m_dead{false}
|
||||
, m_hasGParam{false}
|
||||
, m_hasParameterList{false}
|
||||
, m_hierBlock{false}
|
||||
, m_internal{false}
|
||||
, m_recursive{false}
|
||||
@@ -270,6 +283,8 @@ public:
|
||||
bool dead() const { return m_dead; }
|
||||
void hasGParam(bool flag) { m_hasGParam = flag; }
|
||||
bool hasGParam() const { return m_hasGParam; }
|
||||
void hasParameterList(bool flag) { m_hasParameterList = flag; }
|
||||
bool hasParameterList() const { return m_hasParameterList; }
|
||||
void hierBlock(bool flag) { m_hierBlock = flag; }
|
||||
bool hierBlock() const { return m_hierBlock; }
|
||||
void internal(bool flag) { m_internal = flag; }
|
||||
@@ -289,7 +304,7 @@ class AstNodeProcedure VL_NOT_FINAL : public AstNode {
|
||||
// IEEE procedure: initial, final, always
|
||||
// @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only
|
||||
bool m_suspendable : 1; // Is suspendable by a Delay, EventControl, etc.
|
||||
bool m_needProcess : 1; // Implements part of a process that allocates std::process
|
||||
bool m_needProcess : 1; // Uses VlProcess
|
||||
protected:
|
||||
AstNodeProcedure(VNType t, FileLine* fl, AstNode* stmtsp)
|
||||
: AstNode{t, fl} {
|
||||
@@ -469,11 +484,11 @@ public:
|
||||
ASTGEN_MEMBERS_AstNodeReadWriteMem;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return isHex() == static_cast<const AstNodeReadWriteMem*>(samep)->isHex();
|
||||
return isHex() == VN_DBG_AS(samep, NodeReadWriteMem)->isHex();
|
||||
}
|
||||
bool isHex() const { return m_isHex; }
|
||||
virtual const char* cFuncPrefixp() const = 0;
|
||||
@@ -492,7 +507,7 @@ public:
|
||||
ASTGEN_MEMBERS_AstNodeText;
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstNodeText* asamep = static_cast<const AstNodeText*>(samep);
|
||||
const AstNodeText* asamep = VN_DBG_AS(samep, NodeText);
|
||||
return text() == asamep->text();
|
||||
}
|
||||
const string& text() const VL_MT_SAFE { return m_text; }
|
||||
@@ -597,7 +612,8 @@ private:
|
||||
bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user)
|
||||
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
|
||||
bool m_dpiTraceInit : 1; // DPI trace_init
|
||||
bool m_needProcess : 1; // Implements part of a process that allocates std::process
|
||||
bool m_needProcess : 1; // Needs access to VlProcess of the caller
|
||||
bool m_recursive : 1; // Recursive or part of recursion
|
||||
public:
|
||||
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
|
||||
: ASTGEN_SUPER_CFunc(fl) {
|
||||
@@ -626,6 +642,7 @@ public:
|
||||
m_dpiImportPrototype = false;
|
||||
m_dpiImportWrapper = false;
|
||||
m_dpiTraceInit = false;
|
||||
m_recursive = false;
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCFunc;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
@@ -634,7 +651,7 @@ public:
|
||||
bool maybePointedTo() const override { return true; }
|
||||
void dump(std::ostream& str = std::cout) const override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstCFunc* const asamep = static_cast<const AstCFunc*>(samep);
|
||||
const AstCFunc* const asamep = VN_DBG_AS(samep, CFunc);
|
||||
return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid())
|
||||
&& (argTypes() == asamep->argTypes()) && (baseCtors() == asamep->baseCtors())
|
||||
&& isLoose() == asamep->isLoose()
|
||||
@@ -705,6 +722,8 @@ public:
|
||||
void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
|
||||
bool dpiTraceInit() const { return m_dpiTraceInit; }
|
||||
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
|
||||
void recursive(bool flag) { m_recursive = flag; }
|
||||
bool recursive() const { return m_recursive; }
|
||||
// Special methods
|
||||
bool emptyBody() const {
|
||||
return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr
|
||||
@@ -758,13 +777,14 @@ class AstCell final : public AstNode {
|
||||
// @astgen op1 := pinsp : List[AstPin] // List of port assignments
|
||||
// @astgen op2 := paramsp : List[AstPin] // List of parameter assignments
|
||||
// @astgen op3 := rangep : Optional[AstRange] // Range for arrayed instances
|
||||
// @astgen op4 := intfRefsp : List[AstIntfRef] // List of interface references
|
||||
// @astgen op4 := intfRefsp : List[AstIntfRef] // List of interface references, for tracing
|
||||
FileLine* m_modNameFileline; // Where module the cell instances token was
|
||||
string m_name; // Cell name
|
||||
string m_origName; // Original name before dot addition
|
||||
string m_modName; // Module the cell instances
|
||||
AstNodeModule* m_modp = nullptr; // [AfterLink] Pointer to module instanced
|
||||
bool m_hasIfaceVar : 1; // True if a Var has been created for this cell
|
||||
bool m_hasNoParens : 1; // Instantiation has no parenthesis
|
||||
bool m_recursive : 1; // Self-recursive module
|
||||
bool m_trace : 1; // Trace this cell
|
||||
public:
|
||||
@@ -776,6 +796,7 @@ public:
|
||||
, m_origName{instName}
|
||||
, m_modName{modName}
|
||||
, m_hasIfaceVar{false}
|
||||
, m_hasNoParens{false}
|
||||
, m_recursive{false}
|
||||
, m_trace{true} {
|
||||
this->addPinsp(pinsp);
|
||||
@@ -799,6 +820,8 @@ public:
|
||||
void modp(AstNodeModule* nodep) { m_modp = nodep; }
|
||||
bool hasIfaceVar() const { return m_hasIfaceVar; }
|
||||
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
|
||||
bool hasNoParens() const { return m_hasNoParens; }
|
||||
void hasNoParens(bool flag) { m_hasNoParens = flag; }
|
||||
void trace(bool flag) { m_trace = flag; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
void recursive(bool flag) { m_recursive = flag; }
|
||||
@@ -994,11 +1017,11 @@ public:
|
||||
string verilogKwd() const override { return string{"$"} + string{displayType().ascii()}; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isOutputter() const override { return true; } // SPECIAL: $display makes output
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isOutputter() override { return true; } // SPECIAL: $display makes output
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return displayType() == static_cast<const AstElabDisplay*>(samep)->displayType();
|
||||
return displayType() == VN_DBG_AS(samep, ElabDisplay)->displayType();
|
||||
}
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
VDisplayType displayType() const { return m_displayType; }
|
||||
@@ -1027,7 +1050,7 @@ class AstExecGraph final : public AstNode {
|
||||
const string m_name; // Name of this AstExecGraph (for uniqueness at code generation)
|
||||
|
||||
public:
|
||||
explicit AstExecGraph(FileLine* fl, const string& name);
|
||||
explicit AstExecGraph(FileLine* fl, const string& name) VL_MT_DISABLED;
|
||||
ASTGEN_MEMBERS_AstExecGraph;
|
||||
~AstExecGraph() override;
|
||||
const char* broken() const override {
|
||||
@@ -1176,6 +1199,8 @@ class AstNetlist final : public AstNode {
|
||||
AstCFunc* m_evalNbap = nullptr; // The '_eval__nba' function
|
||||
AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable
|
||||
AstVar* m_delaySchedulerp = nullptr; // The delay scheduler variable
|
||||
AstVarScope* m_nbaEventp = nullptr; // The NBA event variable
|
||||
AstVarScope* m_nbaEventTriggerp = nullptr; // If set to 1, the NBA event should get triggered
|
||||
AstTopScope* m_topScopep = nullptr; // The singleton AstTopScope under the top module
|
||||
VTimescale m_timeunit; // Global time unit
|
||||
VTimescale m_timeprecision; // Global time precision
|
||||
@@ -1205,6 +1230,10 @@ public:
|
||||
void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
|
||||
AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
|
||||
void delaySchedulerp(AstVar* const varScopep) { m_delaySchedulerp = varScopep; }
|
||||
AstVarScope* nbaEventp() const { return m_nbaEventp; }
|
||||
void nbaEventp(AstVarScope* const varScopep) { m_nbaEventp = varScopep; }
|
||||
AstVarScope* nbaEventTriggerp() const { return m_nbaEventTriggerp; }
|
||||
void nbaEventTriggerp(AstVarScope* const varScopep) { m_nbaEventTriggerp = varScopep; }
|
||||
void stdPackagep(AstPackage* const packagep) { m_stdPackagep = packagep; }
|
||||
AstPackage* stdPackagep() const { return m_stdPackagep; }
|
||||
AstTopScope* topScopep() const { return m_topScopep; }
|
||||
@@ -1332,7 +1361,7 @@ public:
|
||||
VPragmaType pragType() const { return m_pragType; } // *=type of the pragma
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return pragType() == static_cast<const AstPragma*>(samep)->pragType();
|
||||
return pragType() == VN_DBG_AS(samep, Pragma)->pragType();
|
||||
}
|
||||
};
|
||||
class AstPropSpec final : public AstNode {
|
||||
@@ -1367,7 +1396,7 @@ public:
|
||||
}
|
||||
ASTGEN_MEMBERS_AstPull;
|
||||
bool same(const AstNode* samep) const override {
|
||||
return direction() == static_cast<const AstPull*>(samep)->direction();
|
||||
return direction() == VN_DBG_AS(samep, Pull)->direction();
|
||||
}
|
||||
uint32_t direction() const { return (uint32_t)m_direction; }
|
||||
};
|
||||
@@ -1447,7 +1476,7 @@ public:
|
||||
ASTGEN_MEMBERS_AstSenItem;
|
||||
void dump(std::ostream& str) const override;
|
||||
bool same(const AstNode* samep) const override {
|
||||
return edgeType() == static_cast<const AstSenItem*>(samep)->edgeType();
|
||||
return edgeType() == VN_DBG_AS(samep, SenItem)->edgeType();
|
||||
}
|
||||
VEdgeType edgeType() const { return m_edgeType; }
|
||||
void edgeType(VEdgeType type) {
|
||||
@@ -1648,12 +1677,11 @@ class AstVar final : public AstNode {
|
||||
VVarType m_varType; // Type of variable
|
||||
VDirection m_direction; // Direction input/output etc
|
||||
VDirection m_declDirection; // Declared direction input/output etc
|
||||
VBasicDTypeKwd m_declKwd; // Keyword at declaration time
|
||||
VLifetime m_lifetime; // Lifetime
|
||||
VVarAttrClocker m_attrClocker;
|
||||
MTaskIdSet m_mtaskIds; // MTaskID's that read or write this var
|
||||
int m_pinNum = 0; // For XML, if non-zero the connection pin number
|
||||
bool m_ansi : 1; // ANSI port list variable (for dedup check)
|
||||
bool m_ansi : 1; // Params or pins declared in the module header, rather than the body
|
||||
bool m_declTyped : 1; // Declared as type (for dedup check)
|
||||
bool m_tristate : 1; // Inout or triwire or trireg
|
||||
bool m_primaryIO : 1; // In/out to top level (or directly assigned from same)
|
||||
@@ -1677,6 +1705,7 @@ class AstVar final : public AstNode {
|
||||
bool m_attrSplitVar : 1; // declared with split_var metacomment
|
||||
bool m_fileDescr : 1; // File descriptor
|
||||
bool m_isRand : 1; // Random variable
|
||||
bool m_isRandC : 1; // Random cyclic variable (isRand also set)
|
||||
bool m_isConst : 1; // Table contains constant data
|
||||
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
|
||||
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
|
||||
@@ -1684,6 +1713,7 @@ class AstVar final : public AstNode {
|
||||
bool m_isPulldown : 1; // Tri0
|
||||
bool m_isPullup : 1; // Tri1
|
||||
bool m_isIfaceParent : 1; // dtype is reference to interface present in this module
|
||||
bool m_isInternal : 1; // Internal state, don't add to method pinter
|
||||
bool m_isDpiOpenArray : 1; // DPI import open array
|
||||
bool m_isHideLocal : 1; // Verilog local
|
||||
bool m_isHideProtected : 1; // Verilog protected
|
||||
@@ -1721,6 +1751,7 @@ class AstVar final : public AstNode {
|
||||
m_attrSplitVar = false;
|
||||
m_fileDescr = false;
|
||||
m_isRand = false;
|
||||
m_isRandC = false;
|
||||
m_isConst = false;
|
||||
m_isContinuously = false;
|
||||
m_hasStrengthAssignment = false;
|
||||
@@ -1728,6 +1759,7 @@ class AstVar final : public AstNode {
|
||||
m_isPulldown = false;
|
||||
m_isPullup = false;
|
||||
m_isIfaceParent = false;
|
||||
m_isInternal = false;
|
||||
m_isDpiOpenArray = false;
|
||||
m_isHideLocal = false;
|
||||
m_isHideProtected = false;
|
||||
@@ -1751,11 +1783,6 @@ public:
|
||||
combineType(type);
|
||||
childDTypep(dtp); // Only for parser
|
||||
dtypep(nullptr); // V3Width will resolve
|
||||
if (dtp->basicp()) {
|
||||
m_declKwd = dtp->basicp()->keyword();
|
||||
} else {
|
||||
m_declKwd = VBasicDTypeKwd::LOGIC;
|
||||
}
|
||||
}
|
||||
AstVar(FileLine* fl, VVarType type, const string& name, AstNodeDType* dtp)
|
||||
: ASTGEN_SUPER_Var(fl)
|
||||
@@ -1765,11 +1792,6 @@ public:
|
||||
combineType(type);
|
||||
UASSERT(dtp, "AstVar created with no dtype");
|
||||
dtypep(dtp);
|
||||
if (dtp->basicp()) {
|
||||
m_declKwd = dtp->basicp()->keyword();
|
||||
} else {
|
||||
m_declKwd = VBasicDTypeKwd::LOGIC;
|
||||
}
|
||||
}
|
||||
AstVar(FileLine* fl, VVarType type, const string& name, VFlagLogicPacked, int wantwidth)
|
||||
: ASTGEN_SUPER_Var(fl)
|
||||
@@ -1778,7 +1800,6 @@ public:
|
||||
init();
|
||||
combineType(type);
|
||||
dtypeSetLogicSized(wantwidth, VSigning::UNSIGNED);
|
||||
m_declKwd = VBasicDTypeKwd::LOGIC;
|
||||
}
|
||||
AstVar(FileLine* fl, VVarType type, const string& name, VFlagBitPacked, int wantwidth)
|
||||
: ASTGEN_SUPER_Var(fl)
|
||||
@@ -1787,7 +1808,6 @@ public:
|
||||
init();
|
||||
combineType(type);
|
||||
dtypeSetBitSized(wantwidth, VSigning::UNSIGNED);
|
||||
m_declKwd = VBasicDTypeKwd::BIT;
|
||||
}
|
||||
AstVar(FileLine* fl, VVarType type, const string& name, AstVar* examplep)
|
||||
: ASTGEN_SUPER_Var(fl)
|
||||
@@ -1797,7 +1817,6 @@ public:
|
||||
combineType(type);
|
||||
if (examplep->childDTypep()) childDTypep(examplep->childDTypep()->cloneTree(true));
|
||||
dtypeFrom(examplep);
|
||||
m_declKwd = examplep->declKwd();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstVar;
|
||||
void dump(std::ostream& str) const override;
|
||||
@@ -1825,7 +1844,6 @@ public:
|
||||
m_tristate = false;
|
||||
m_direction = VDirection::INPUT;
|
||||
}
|
||||
VBasicDTypeKwd declKwd() const { return m_declKwd; }
|
||||
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
|
||||
// Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
||||
string cPubArgType(bool named, bool forReturn) const;
|
||||
@@ -1873,10 +1891,15 @@ public:
|
||||
void scSensitive(bool flag) { m_scSensitive = flag; }
|
||||
void primaryIO(bool flag) { m_primaryIO = flag; }
|
||||
void isRand(bool flag) { m_isRand = flag; }
|
||||
void isRandC(bool flag) {
|
||||
m_isRandC = flag;
|
||||
if (flag) isRand(true);
|
||||
}
|
||||
void isConst(bool flag) { m_isConst = flag; }
|
||||
void isContinuously(bool flag) { m_isContinuously = flag; }
|
||||
void isStatic(bool flag) { m_isStatic = flag; }
|
||||
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
|
||||
void isInternal(bool flag) { m_isInternal = flag; }
|
||||
void funcLocal(bool flag) {
|
||||
m_funcLocal = flag;
|
||||
if (flag) m_funcLocalSticky = true;
|
||||
@@ -1915,12 +1938,15 @@ public:
|
||||
bool isInoutish() const { return m_direction.isInoutish(); }
|
||||
bool isNonOutput() const { return m_direction.isNonOutput(); }
|
||||
bool isReadOnly() const VL_MT_SAFE { return m_direction.isReadOnly(); }
|
||||
bool isConstRef() const VL_MT_SAFE { return m_direction.isConstRef(); }
|
||||
bool isRef() const VL_MT_SAFE { return m_direction.isRef(); }
|
||||
bool isWritable() const VL_MT_SAFE { return m_direction.isWritable(); }
|
||||
bool isTristate() const { return m_tristate; }
|
||||
bool isPrimaryIO() const { return m_primaryIO; }
|
||||
bool isPrimaryInish() const { return isPrimaryIO() && isNonOutput(); }
|
||||
bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); }
|
||||
bool isIfaceParent() const { return m_isIfaceParent; }
|
||||
bool isInternal() const { return m_isInternal; }
|
||||
bool isSignal() const { return varType().isSignal(); }
|
||||
bool isNet() const { return varType().isNet(); }
|
||||
bool isTemp() const { return varType().isTemp(); }
|
||||
@@ -1956,6 +1982,7 @@ public:
|
||||
bool isSigUserRWPublic() const { return m_sigUserRWPublic; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
bool isRand() const { return m_isRand; }
|
||||
bool isRandC() const { return m_isRandC; }
|
||||
bool isConst() const VL_MT_SAFE { return m_isConst; }
|
||||
bool isStatic() const VL_MT_SAFE { return m_isStatic; }
|
||||
bool isLatched() const { return m_isLatched; }
|
||||
@@ -2068,19 +2095,23 @@ class AstBegin final : public AstNodeBlock {
|
||||
// Parents: statement
|
||||
// @astgen op1 := genforp : Optional[AstNode]
|
||||
|
||||
bool m_generate; // Underneath a generate
|
||||
const bool m_implied; // Not inserted by user
|
||||
bool m_generate : 1; // Underneath a generate
|
||||
bool m_needProcess : 1; // Uses VlProcess
|
||||
const bool m_implied : 1; // Not inserted by user
|
||||
public:
|
||||
// Node that puts name into the output stream
|
||||
AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false,
|
||||
bool implied = false)
|
||||
: ASTGEN_SUPER_Begin(fl, name, stmtsp)
|
||||
, m_generate{generate}
|
||||
, m_needProcess{false}
|
||||
, m_implied{implied} {}
|
||||
ASTGEN_MEMBERS_AstBegin;
|
||||
void dump(std::ostream& str) const override;
|
||||
void generate(bool flag) { m_generate = flag; }
|
||||
bool generate() const { return m_generate; }
|
||||
void setNeedProcess() { m_needProcess = true; }
|
||||
bool needProcess() const { return m_needProcess; }
|
||||
bool implied() const { return m_implied; }
|
||||
};
|
||||
class AstFork final : public AstNodeBlock {
|
||||
@@ -2583,7 +2614,7 @@ public:
|
||||
void hier(const string& flag) { m_hier = flag; }
|
||||
void comment(const string& flag) { m_text = flag; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
const AstCoverDecl* const asamep = static_cast<const AstCoverDecl*>(samep);
|
||||
const AstCoverDecl* const asamep = VN_DBG_AS(samep, CoverDecl);
|
||||
return (fileline() == asamep->fileline() && linescov() == asamep->linescov()
|
||||
&& hier() == asamep->hier() && comment() == asamep->comment());
|
||||
}
|
||||
@@ -2612,11 +2643,11 @@ public:
|
||||
void dump(std::ostream& str) const override;
|
||||
int instrCount() const override { return 1 + 2 * INSTR_COUNT_LD; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return declp() == static_cast<const AstCoverInc*>(samep)->declp();
|
||||
return declp() == VN_DBG_AS(samep, CoverInc)->declp();
|
||||
}
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isOutputter() override { return true; }
|
||||
// but isPure() true
|
||||
AstCoverDecl* declp() const { return m_declp; } // Where defined
|
||||
};
|
||||
@@ -2638,7 +2669,7 @@ public:
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return true; }
|
||||
bool isOutputter() const override {
|
||||
bool isOutputter() override {
|
||||
return false; // Though the AstCoverInc under this is an outputter
|
||||
}
|
||||
// but isPure() true
|
||||
@@ -2715,11 +2746,11 @@ public:
|
||||
}
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isOutputter() const override { return true; } // SPECIAL: $display makes output
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isOutputter() override { return true; } // SPECIAL: $display makes output
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return displayType() == static_cast<const AstDisplay*>(samep)->displayType();
|
||||
return displayType() == VN_DBG_AS(samep, Display)->displayType();
|
||||
}
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
VDisplayType displayType() const { return m_displayType; }
|
||||
@@ -2758,7 +2789,7 @@ public:
|
||||
string verilogKwd() const override { return ctlType().ascii(); }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isOutputter() override { return true; }
|
||||
virtual bool cleanOut() const { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
VDumpCtlType ctlType() const { return m_ctlType; }
|
||||
@@ -2790,8 +2821,8 @@ public:
|
||||
string verilogKwd() const override { return "$fclose"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -2807,8 +2838,8 @@ public:
|
||||
string verilogKwd() const override { return "$fflush"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -2819,8 +2850,8 @@ public:
|
||||
ASTGEN_MEMBERS_AstFinish;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isOutputter() const override { return true; } // SPECIAL: $display makes output
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isOutputter() override { return true; } // SPECIAL: $display makes output
|
||||
bool isUnlikely() const override { return true; }
|
||||
int instrCount() const override { return 0; } // Rarely executes
|
||||
bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
|
||||
@@ -2896,7 +2927,7 @@ public:
|
||||
void dump(std::ostream& str) const override;
|
||||
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return labelp() == static_cast<const AstJumpGo*>(samep)->labelp();
|
||||
return labelp() == VN_DBG_AS(samep, JumpGo)->labelp();
|
||||
}
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isBrancher() const override {
|
||||
@@ -2927,7 +2958,7 @@ public:
|
||||
void dump(std::ostream& str) const override;
|
||||
int instrCount() const override { return 0; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return blockp() == static_cast<const AstJumpLabel*>(samep)->blockp();
|
||||
return blockp() == VN_DBG_AS(samep, JumpLabel)->blockp();
|
||||
}
|
||||
AstJumpBlock* blockp() const { return m_blockp; }
|
||||
};
|
||||
@@ -2942,11 +2973,11 @@ public:
|
||||
string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; }
|
||||
bool isGateOptimizable() const override { return false; } // Though deleted before opt
|
||||
bool isPredictOptimizable() const override { return false; } // Though deleted before opt
|
||||
bool isPure() const override { return false; } // Though deleted before opt
|
||||
bool isOutputter() const override { return true; } // Though deleted before opt
|
||||
bool isPure() override { return false; } // Though deleted before opt
|
||||
bool isOutputter() override { return true; } // Though deleted before opt
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return m_off == static_cast<const AstMonitorOff*>(samep)->m_off;
|
||||
return m_off == VN_DBG_AS(samep, MonitorOff)->m_off;
|
||||
}
|
||||
bool off() const { return m_off; }
|
||||
};
|
||||
@@ -2964,8 +2995,8 @@ public:
|
||||
string verilogKwd() const override { return "$printtimescale"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
void timeunit(const VTimescale& flag) { m_timeunit = flag; }
|
||||
VTimescale timeunit() const { return m_timeunit; }
|
||||
@@ -3042,8 +3073,8 @@ public:
|
||||
string verilogKwd() const override { return "$sformat"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return true; }
|
||||
bool isPure() const override { return true; }
|
||||
bool isOutputter() const override { return false; }
|
||||
bool isPure() override { return true; }
|
||||
bool isOutputter() override { return false; }
|
||||
virtual bool cleanOut() const { return false; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
@@ -3057,8 +3088,8 @@ public:
|
||||
string verilogKwd() const override { return "$stacktrace"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -3079,8 +3110,8 @@ public:
|
||||
ASTGEN_MEMBERS_AstStop;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isOutputter() const override { return true; } // SPECIAL: $display makes output
|
||||
bool isPure() override { return false; } // SPECIAL: $display has 'visual' ordering
|
||||
bool isOutputter() override { return true; } // SPECIAL: $display makes output
|
||||
bool isUnlikely() const override { return true; }
|
||||
int instrCount() const override { return 0; } // Rarely executes
|
||||
bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); }
|
||||
@@ -3098,8 +3129,8 @@ public:
|
||||
string verilogKwd() const override { return ""; }
|
||||
bool isGateOptimizable() const override { return true; }
|
||||
bool isPredictOptimizable() const override { return true; }
|
||||
bool isPure() const override { return true; }
|
||||
bool isOutputter() const override { return false; }
|
||||
bool isPure() override { return true; }
|
||||
bool isOutputter() override { return false; }
|
||||
int instrCount() const override { return 0; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -3115,8 +3146,8 @@ public:
|
||||
string verilogKwd() const override { return "$system"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
@@ -3139,8 +3170,8 @@ public:
|
||||
string verilogKwd() const override { return "$timeformat"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
};
|
||||
class AstTraceDecl final : public AstNodeStmt {
|
||||
@@ -3150,13 +3181,13 @@ class AstTraceDecl final : public AstNodeStmt {
|
||||
// Expression being traced - Moved to AstTraceInc by V3Trace
|
||||
// @astgen op1 := valuep : Optional[AstNodeExpr]
|
||||
private:
|
||||
uint32_t m_code = 0; // Trace identifier code; converted to ASCII by trace routines
|
||||
uint32_t m_code{0}; // Trace identifier code
|
||||
uint32_t m_fidx{0}; // Trace function index
|
||||
const string m_showname; // Name of variable
|
||||
const VNumRange m_bitRange; // Property of var the trace details
|
||||
const VNumRange m_arrayRange; // Property of var the trace details
|
||||
const uint32_t m_codeInc; // Code increment
|
||||
const VVarType m_varType; // Type of variable (for localparam vs. param)
|
||||
const VBasicDTypeKwd m_declKwd; // Keyword at declaration time
|
||||
const VDirection m_declDirection; // Declared direction input/output etc
|
||||
public:
|
||||
AstTraceDecl(FileLine* fl, const string& showname,
|
||||
@@ -3170,7 +3201,6 @@ public:
|
||||
((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords()
|
||||
* (VL_EDATASIZE / 32))) // A code is always 32-bits
|
||||
, m_varType{varp->varType()}
|
||||
, m_declKwd{varp->declKwd()}
|
||||
, m_declDirection{varp->declDirection()} {
|
||||
dtypeFrom(valuep);
|
||||
this->valuep(valuep);
|
||||
@@ -3186,11 +3216,12 @@ public:
|
||||
// Details on what we're tracing
|
||||
uint32_t code() const { return m_code; }
|
||||
void code(uint32_t code) { m_code = code; }
|
||||
uint32_t fidx() const { return m_fidx; }
|
||||
void fidx(uint32_t fidx) { m_fidx = fidx; }
|
||||
uint32_t codeInc() const { return m_codeInc; }
|
||||
const VNumRange& bitRange() const { return m_bitRange; }
|
||||
const VNumRange& arrayRange() const { return m_arrayRange; }
|
||||
VVarType varType() const { return m_varType; }
|
||||
VBasicDTypeKwd declKwd() const { return m_declKwd; }
|
||||
VDirection declDirection() const { return m_declDirection; }
|
||||
};
|
||||
class AstTraceInc final : public AstNodeStmt {
|
||||
@@ -3201,14 +3232,14 @@ class AstTraceInc final : public AstNodeStmt {
|
||||
private:
|
||||
AstTraceDecl* m_declp; // Pointer to declaration
|
||||
const uint32_t m_baseCode; // Trace code base value in function containing this AstTraceInc
|
||||
const bool m_full; // Is this a full vs incremental dump
|
||||
const VTraceType m_traceType; // Is this a const/full/incremental dump
|
||||
|
||||
public:
|
||||
AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full, uint32_t baseCode = 0)
|
||||
AstTraceInc(FileLine* fl, AstTraceDecl* declp, VTraceType traceType, uint32_t baseCode = 0)
|
||||
: ASTGEN_SUPER_TraceInc(fl)
|
||||
, m_declp{declp}
|
||||
, m_baseCode{baseCode}
|
||||
, m_full{full} {
|
||||
, m_traceType{traceType} {
|
||||
dtypeFrom(declp);
|
||||
this->valuep(
|
||||
declp->valuep()->cloneTree(true)); // TODO: maybe use reference to TraceDecl instead?
|
||||
@@ -3225,35 +3256,35 @@ public:
|
||||
int instrCount() const override { return 10 + 2 * INSTR_COUNT_LD; }
|
||||
bool hasDType() const override { return true; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return declp() == static_cast<const AstTraceInc*>(samep)->declp();
|
||||
return declp() == VN_DBG_AS(samep, TraceInc)->declp();
|
||||
}
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isOutputter() override { return true; }
|
||||
// but isPure() true
|
||||
AstTraceDecl* declp() const { return m_declp; }
|
||||
bool full() const { return m_full; }
|
||||
VTraceType traceType() const { return m_traceType; }
|
||||
uint32_t baseCode() const { return m_baseCode; }
|
||||
};
|
||||
class AstTracePopNamePrefix final : public AstNodeStmt {
|
||||
const unsigned m_count; // How many levels to pop
|
||||
class AstTracePopPrefix final : public AstNodeStmt {
|
||||
public:
|
||||
AstTracePopNamePrefix(FileLine* fl, unsigned count)
|
||||
: ASTGEN_SUPER_TracePopNamePrefix(fl)
|
||||
, m_count{count} {}
|
||||
ASTGEN_MEMBERS_AstTracePopNamePrefix;
|
||||
AstTracePopPrefix(FileLine* fl)
|
||||
: ASTGEN_SUPER_TracePopPrefix(fl) {}
|
||||
ASTGEN_MEMBERS_AstTracePopPrefix;
|
||||
bool same(const AstNode* samep) const override { return false; }
|
||||
unsigned count() const { return m_count; }
|
||||
};
|
||||
class AstTracePushNamePrefix final : public AstNodeStmt {
|
||||
class AstTracePushPrefix final : public AstNodeStmt {
|
||||
const string m_prefix; // Prefix to add to signal names
|
||||
const VTracePrefixType m_prefixType; // Type of prefix being pushed
|
||||
public:
|
||||
AstTracePushNamePrefix(FileLine* fl, const string& prefix)
|
||||
: ASTGEN_SUPER_TracePushNamePrefix(fl)
|
||||
, m_prefix{prefix} {}
|
||||
ASTGEN_MEMBERS_AstTracePushNamePrefix;
|
||||
AstTracePushPrefix(FileLine* fl, const string& prefix, VTracePrefixType prefixType)
|
||||
: ASTGEN_SUPER_TracePushPrefix(fl)
|
||||
, m_prefix{prefix}
|
||||
, m_prefixType{prefixType} {}
|
||||
ASTGEN_MEMBERS_AstTracePushPrefix;
|
||||
bool same(const AstNode* samep) const override { return false; }
|
||||
string prefix() const { return m_prefix; }
|
||||
VTracePrefixType prefixType() const { return m_prefixType; }
|
||||
};
|
||||
class AstUCStmt final : public AstNodeStmt {
|
||||
// User $c statement
|
||||
@@ -3266,8 +3297,8 @@ public:
|
||||
ASTGEN_MEMBERS_AstUCStmt;
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; }
|
||||
bool isOutputter() override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstWait final : public AstNodeStmt {
|
||||
@@ -3289,6 +3320,7 @@ public:
|
||||
explicit AstWaitFork(FileLine* fl)
|
||||
: ASTGEN_SUPER_WaitFork(fl) {}
|
||||
ASTGEN_MEMBERS_AstWaitFork;
|
||||
bool isTimingControl() const override { return true; }
|
||||
};
|
||||
class AstWhile final : public AstNodeStmt {
|
||||
// @astgen op1 := precondsp : List[AstNode]
|
||||
@@ -3435,7 +3467,7 @@ public:
|
||||
ASTGEN_MEMBERS_AstCase;
|
||||
string verilogKwd() const override { return casez() ? "casez" : casex() ? "casex" : "case"; }
|
||||
bool same(const AstNode* samep) const override {
|
||||
return m_casex == static_cast<const AstCase*>(samep)->m_casex;
|
||||
return m_casex == VN_DBG_AS(samep, Case)->m_casex;
|
||||
}
|
||||
bool casex() const { return m_casex == VCaseType::CT_CASEX; }
|
||||
bool casez() const { return m_casex == VCaseType::CT_CASEZ; }
|
||||
@@ -3557,48 +3589,48 @@ public:
|
||||
AstScCtor(FileLine* fl, const string& textp)
|
||||
: ASTGEN_SUPER_ScCtor(fl, textp) {}
|
||||
ASTGEN_MEMBERS_AstScCtor;
|
||||
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() override { return true; }
|
||||
};
|
||||
class AstScDtor final : public AstNodeText {
|
||||
public:
|
||||
AstScDtor(FileLine* fl, const string& textp)
|
||||
: ASTGEN_SUPER_ScDtor(fl, textp) {}
|
||||
ASTGEN_MEMBERS_AstScDtor;
|
||||
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() override { return true; }
|
||||
};
|
||||
class AstScHdr final : public AstNodeText {
|
||||
public:
|
||||
AstScHdr(FileLine* fl, const string& textp)
|
||||
: ASTGEN_SUPER_ScHdr(fl, textp) {}
|
||||
ASTGEN_MEMBERS_AstScHdr;
|
||||
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() override { return true; }
|
||||
};
|
||||
class AstScImp final : public AstNodeText {
|
||||
public:
|
||||
AstScImp(FileLine* fl, const string& textp)
|
||||
: ASTGEN_SUPER_ScImp(fl, textp) {}
|
||||
ASTGEN_MEMBERS_AstScImp;
|
||||
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() override { return true; }
|
||||
};
|
||||
class AstScImpHdr final : public AstNodeText {
|
||||
public:
|
||||
AstScImpHdr(FileLine* fl, const string& textp)
|
||||
: ASTGEN_SUPER_ScImpHdr(fl, textp) {}
|
||||
ASTGEN_MEMBERS_AstScImpHdr;
|
||||
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() override { return true; }
|
||||
};
|
||||
class AstScInt final : public AstNodeText {
|
||||
public:
|
||||
AstScInt(FileLine* fl, const string& textp)
|
||||
: ASTGEN_SUPER_ScInt(fl, textp) {}
|
||||
ASTGEN_MEMBERS_AstScInt;
|
||||
bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isPure() override { return false; } // SPECIAL: User may order w/other sigs
|
||||
bool isOutputter() override { return true; }
|
||||
};
|
||||
|
||||
// === AstNodeSimpleText ===
|
||||
|
||||
+160
-66
@@ -14,18 +14,14 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstMT.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3Hasher.h"
|
||||
#include "V3PartitionGraph.h" // Just for mtask dumping
|
||||
#include "V3String.h"
|
||||
#include "V3Width.h"
|
||||
|
||||
#include "V3Ast__gen_macros.h" // Generated by 'astgen'
|
||||
|
||||
@@ -51,6 +47,7 @@ AstIface* AstIfaceRefDType::ifaceViaCellp() const {
|
||||
const char* AstNodeFTaskRef::broken() const {
|
||||
BROKEN_RTN(m_taskp && !m_taskp->brokeExists());
|
||||
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
||||
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -61,12 +58,29 @@ void AstNodeFTaskRef::cloneRelink() {
|
||||
}
|
||||
}
|
||||
|
||||
bool AstNodeFTaskRef::isPure() const {
|
||||
// TODO: For non-DPI functions we could traverse the AST of function's body to determine
|
||||
// pureness.
|
||||
return this->taskp() && this->taskp()->dpiImport() && this->taskp()->dpiPure();
|
||||
bool AstNodeFTaskRef::isPure() {
|
||||
if (!this->taskp()) {
|
||||
// The task isn't linked yet, so it's assumed that it is impure, but the value shouldn't be
|
||||
// cached.
|
||||
return false;
|
||||
} else {
|
||||
if (!m_purity.isCached()) m_purity.set(this->getPurityRecurse());
|
||||
return m_purity.get();
|
||||
}
|
||||
}
|
||||
|
||||
bool AstNodeFTaskRef::getPurityRecurse() const {
|
||||
AstNodeFTask* const taskp = this->taskp();
|
||||
// Unlinked yet, so treat as impure
|
||||
if (!taskp) return false;
|
||||
|
||||
// First compute the purity of arguments
|
||||
for (AstNode* pinp = this->pinsp(); pinp; pinp = pinp->nextp()) {
|
||||
if (!pinp->isPure()) return false;
|
||||
}
|
||||
|
||||
return taskp->isPure();
|
||||
}
|
||||
bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); }
|
||||
|
||||
const char* AstNodeVarRef::broken() const {
|
||||
@@ -121,7 +135,50 @@ const char* AstNodeCCall::broken() const {
|
||||
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
|
||||
return nullptr;
|
||||
}
|
||||
bool AstNodeCCall::isPure() const { return funcp()->dpiPure(); }
|
||||
bool AstNodeCCall::isPure() { return funcp()->dpiPure(); }
|
||||
bool AstNodeUniop::isPure() {
|
||||
if (!m_purity.isCached()) m_purity.set(lhsp()->isPure());
|
||||
return m_purity.get();
|
||||
}
|
||||
const char* AstNodeUniop::broken() const {
|
||||
BROKEN_RTN(m_purity.isCached() && m_purity.get() != lhsp()->isPure());
|
||||
return nullptr;
|
||||
}
|
||||
bool AstNodeBiop::isPure() {
|
||||
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
||||
return m_purity.get();
|
||||
}
|
||||
const char* AstNodeBiop::broken() const {
|
||||
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AstNodeTriop::isPure() {
|
||||
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
||||
return m_purity.get();
|
||||
}
|
||||
const char* AstNodeTriop::broken() const {
|
||||
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AstNodePreSel::isPure() {
|
||||
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
||||
return m_purity.get();
|
||||
}
|
||||
const char* AstNodePreSel::broken() const {
|
||||
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AstNodeQuadop::isPure() {
|
||||
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
||||
return m_purity.get();
|
||||
}
|
||||
const char* AstNodeQuadop::broken() const {
|
||||
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp,
|
||||
AstNodeExpr* elsep)
|
||||
@@ -130,7 +187,7 @@ AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr
|
||||
UASSERT_OBJ(elsep, this, "No elsep expression");
|
||||
if (thenp->isClassHandleValue() && elsep->isClassHandleValue()) {
|
||||
// Get the most-deriving class type that both arguments can be casted to.
|
||||
AstNodeDType* const commonClassTypep = V3Width::getCommonClassTypep(thenp, elsep);
|
||||
AstNodeDType* const commonClassTypep = getCommonClassTypep(thenp, elsep);
|
||||
UASSERT_OBJ(commonClassTypep, this, "No common base class exists");
|
||||
dtypep(commonClassTypep);
|
||||
} else {
|
||||
@@ -216,12 +273,10 @@ int AstBasicDType::widthTotalBytes() const {
|
||||
}
|
||||
|
||||
bool AstBasicDType::same(const AstNode* samep) const {
|
||||
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
|
||||
if (!rangep() && !sp->rangep() && m == sp->m) {
|
||||
return true;
|
||||
} else {
|
||||
return m == sp->m && rangep() && rangep()->sameTree(sp->rangep());
|
||||
}
|
||||
const AstBasicDType* const sp = VN_DBG_AS(samep, BasicDType);
|
||||
if (!(m == sp->m) || numeric() != sp->numeric()) return false;
|
||||
if (!rangep() && !sp->rangep()) return true;
|
||||
return rangep() && rangep()->sameTree(sp->rangep());
|
||||
}
|
||||
|
||||
int AstNodeUOrStructDType::widthTotalBytes() const {
|
||||
@@ -270,17 +325,17 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* r
|
||||
}
|
||||
}
|
||||
|
||||
AstExecGraph::AstExecGraph(FileLine* fileline, const string& name)
|
||||
: ASTGEN_SUPER_ExecGraph(fileline)
|
||||
, m_depGraphp{new V3Graph}
|
||||
, m_name{name} {}
|
||||
AstExecGraph::AstExecGraph(FileLine* fileline, const string& name) VL_MT_DISABLED
|
||||
: ASTGEN_SUPER_ExecGraph(fileline),
|
||||
m_depGraphp{new V3Graph},
|
||||
m_name{name} {}
|
||||
|
||||
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
|
||||
|
||||
AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* lhsp,
|
||||
AstNodeExpr* rhsp) {
|
||||
AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTree(true), lhsp};
|
||||
AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTree(true), rhsp};
|
||||
AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTreePure(true), lhsp};
|
||||
AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTreePure(true), rhsp};
|
||||
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
|
||||
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
|
||||
return new AstAnd{fileline(), ap, bp};
|
||||
@@ -388,7 +443,8 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
|
||||
if (isStatic() && namespc.empty()) ostatic = "static ";
|
||||
|
||||
const bool isRef = isDpiOpenArray()
|
||||
|| (forFunc && (isWritable() || direction().isRefOrConstRef())) || asRef;
|
||||
|| (forFunc && (isWritable() || this->isRef() || this->isConstRef()))
|
||||
|| asRef;
|
||||
|
||||
if (forFunc && isReadOnly() && isRef) ostatic = ostatic + "const ";
|
||||
|
||||
@@ -410,6 +466,8 @@ string AstVar::vlEnumType() const {
|
||||
return "VLVT_PTR";
|
||||
} else if (strtype) {
|
||||
arg += "VLVT_STRING";
|
||||
} else if (isDouble()) {
|
||||
arg += "VLVT_REAL";
|
||||
} else if (widthMin() <= 8) {
|
||||
arg += "VLVT_UINT8";
|
||||
} else if (widthMin() <= 16) {
|
||||
@@ -502,7 +560,7 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named = false;
|
||||
string arg;
|
||||
if (isWide() && isReadOnly()) arg += "const ";
|
||||
const bool isRef = !forReturn && (isWritable() || direction().isRefOrConstRef());
|
||||
const bool isRef = !forReturn && (isWritable() || this->isRef() || this->isConstRef());
|
||||
if (VN_IS(dtypeSkipRefp(), BasicDType) && !dtypeSkipRefp()->isDouble()
|
||||
&& !dtypeSkipRefp()->isString()) {
|
||||
// Backward compatible type declaration
|
||||
@@ -630,13 +688,14 @@ string AstVar::dpiTmpVarType(const string& varName) const {
|
||||
|
||||
string AstVar::scType() const {
|
||||
if (isScBigUint()) {
|
||||
return (string{"sc_biguint<"} + cvtToStr(widthMin())
|
||||
return (string{"sc_dt::sc_biguint<"} + cvtToStr(widthMin())
|
||||
+ "> "); // Keep the space so don't get >>
|
||||
} else if (isScUint()) {
|
||||
return (string{"sc_uint<"} + cvtToStr(widthMin())
|
||||
return (string{"sc_dt::sc_uint<"} + cvtToStr(widthMin())
|
||||
+ "> "); // Keep the space so don't get >>
|
||||
} else if (isScBv()) {
|
||||
return (string{"sc_bv<"} + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >>
|
||||
return (string{"sc_dt::sc_bv<"} + cvtToStr(widthMin())
|
||||
+ "> "); // Keep the space so don't get >>
|
||||
} else if (widthMin() == 1) {
|
||||
return "bool";
|
||||
} else if (widthMin() <= VL_IDATASIZE) {
|
||||
@@ -712,6 +771,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
||||
const CTypeRecursed key = adtypep->keyDTypep()->cTypeRecurse(true);
|
||||
const CTypeRecursed val = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, CDType)) {
|
||||
info.m_type = adtypep->name();
|
||||
} else if (const auto* const adtypep = VN_CAST(dtypep, WildcardArrayDType)) {
|
||||
const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true);
|
||||
info.m_type = "VlAssocArray<std::string, " + sub.m_type + ">";
|
||||
@@ -769,7 +830,7 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const {
|
||||
} else if (bdtypep->isProcessRef()) {
|
||||
info.m_type = "VlProcessRef";
|
||||
} else if (bdtypep->isEvent()) {
|
||||
info.m_type = "VlEvent";
|
||||
info.m_type = v3Global.assignsEvents() ? "VlAssignableEvent" : "VlEvent";
|
||||
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
||||
info.m_type = "CData" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 16) {
|
||||
@@ -1117,13 +1178,10 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
|
||||
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
|
||||
const VBasicTypeKey key{nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
|
||||
nodep->nrange()};
|
||||
DetailedMap& mapr = m_detailedMap;
|
||||
const auto it = mapr.find(key);
|
||||
if (it != mapr.end()) return it->second;
|
||||
mapr.emplace(key, nodep);
|
||||
nodep->generic(true);
|
||||
auto pair = m_detailedMap.emplace(key, nodep);
|
||||
if (pair.second) nodep->generic(true);
|
||||
// No addTypesp; the upper function that called new() is responsible for adding
|
||||
return nodep;
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
AstConstPool::AstConstPool(FileLine* fl)
|
||||
@@ -1321,7 +1379,6 @@ void AstNode::dump(std::ostream& str) const {
|
||||
if (user2p()) str << " u2=" << nodeAddr(user2p());
|
||||
if (user3p()) str << " u3=" << nodeAddr(user3p());
|
||||
if (user4p()) str << " u4=" << nodeAddr(user4p());
|
||||
if (user5p()) str << " u5=" << nodeAddr(user5p());
|
||||
if (hasDType()) {
|
||||
// Final @ so less likely to by accident read it as a nodep
|
||||
if (dtypep() == this) {
|
||||
@@ -1395,7 +1452,7 @@ const char* AstCell::broken() const {
|
||||
void AstCellInline::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " -> " << origModName();
|
||||
str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
||||
str << " [scopep=" << nodeAddr(scopep()) << "]";
|
||||
}
|
||||
const char* AstCellInline::broken() const {
|
||||
BROKEN_RTN(m_scopep && !m_scopep->brokeExists());
|
||||
@@ -1525,6 +1582,12 @@ const char* AstEnumItemRef::broken() const {
|
||||
BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists());
|
||||
return nullptr;
|
||||
}
|
||||
void AstEnumItemRef::cloneRelink() {
|
||||
if (m_itemp->clonep()) m_itemp = m_itemp->clonep();
|
||||
if (m_classOrPackagep && m_classOrPackagep->clonep()) {
|
||||
m_classOrPackagep = m_classOrPackagep->clonep();
|
||||
}
|
||||
}
|
||||
void AstIfaceRefDType::dump(std::ostream& str) const {
|
||||
this->AstNodeDType::dump(str);
|
||||
if (cellName() != "") str << " cell=" << cellName();
|
||||
@@ -1558,7 +1621,7 @@ void AstInitArray::dump(std::ostream& str) const {
|
||||
str << " ...";
|
||||
break;
|
||||
}
|
||||
str << " [" << itr.first << "]=" << reinterpret_cast<const void*>(itr.second);
|
||||
str << " [" << itr.first << "]=" << nodeAddr(itr.second);
|
||||
}
|
||||
}
|
||||
const char* AstInitArray::broken() const {
|
||||
@@ -1574,13 +1637,13 @@ void AstInitArray::cloneRelink() {
|
||||
}
|
||||
}
|
||||
void AstInitArray::addIndexValuep(uint64_t index, AstNodeExpr* newp) {
|
||||
const auto it = m_map.find(index);
|
||||
if (it != m_map.end()) {
|
||||
it->second->valuep(newp);
|
||||
} else {
|
||||
const auto pair = m_map.emplace(index, nullptr);
|
||||
if (pair.second) {
|
||||
AstInitItem* const itemp = new AstInitItem{fileline(), newp};
|
||||
m_map.emplace(index, itemp);
|
||||
pair.first->second = itemp;
|
||||
addInitsp(itemp);
|
||||
} else {
|
||||
pair.first->second->valuep(newp);
|
||||
}
|
||||
}
|
||||
AstNodeExpr* AstInitArray::getIndexValuep(uint64_t index) const {
|
||||
@@ -1622,10 +1685,6 @@ void AstJumpLabel::dump(std::ostream& str) const {
|
||||
str << "%Error:UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstLogOr::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
if (sideEffect()) str << " [SIDE]";
|
||||
}
|
||||
|
||||
void AstMemberDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
@@ -1640,8 +1699,8 @@ AstNodeUOrStructDType* AstMemberDType::getChildStructp() const {
|
||||
}
|
||||
|
||||
bool AstMemberSel::same(const AstNode* samep) const {
|
||||
const AstMemberSel* const sp = static_cast<const AstMemberSel*>(samep);
|
||||
return sp != nullptr && access() == sp->access() && fromp()->same(sp->fromp())
|
||||
const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel);
|
||||
return sp != nullptr && access() == sp->access() && fromp()->isSame(sp->fromp())
|
||||
&& name() == sp->name() && varp()->same(sp->varp());
|
||||
}
|
||||
|
||||
@@ -1876,6 +1935,8 @@ const char* AstNetlist::broken() const {
|
||||
BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists());
|
||||
BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists());
|
||||
BROKEN_RTN(m_delaySchedulerp && !m_delaySchedulerp->brokeExists());
|
||||
BROKEN_RTN(m_nbaEventp && !m_nbaEventp->brokeExists());
|
||||
BROKEN_RTN(m_nbaEventTriggerp && !m_nbaEventTriggerp->brokeExists());
|
||||
return nullptr;
|
||||
}
|
||||
AstPackage* AstNetlist::dollarUnitPkgAddp() {
|
||||
@@ -1974,7 +2035,7 @@ void AstTypeTable::dump(std::ostream& str) const {
|
||||
}
|
||||
void AstAssocArrayDType::dumpSmall(std::ostream& str) const {
|
||||
this->AstNodeDType::dumpSmall(str);
|
||||
str << "[assoc-" << reinterpret_cast<const void*>(keyDTypep()) << "]";
|
||||
str << "[assoc-" << nodeAddr(keyDTypep()) << "]";
|
||||
}
|
||||
string AstAssocArrayDType::prettyDTypeName() const {
|
||||
return subDTypep()->prettyDTypeName() + "[" + keyDTypep()->prettyDTypeName() + "]";
|
||||
@@ -1998,13 +2059,14 @@ void AstWildcardArrayDType::dumpSmall(std::ostream& str) const {
|
||||
str << "[*]";
|
||||
}
|
||||
bool AstWildcardArrayDType::same(const AstNode* samep) const {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep());
|
||||
}
|
||||
bool AstWildcardArrayDType::similarDType(const AstNodeDType* samep) const {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
return type() == samep->type() && asamep->subDTypep()
|
||||
if (type() != samep->type()) return false;
|
||||
const AstWildcardArrayDType* const asamep = VN_DBG_AS(samep, WildcardArrayDType);
|
||||
return asamep->subDTypep()
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||
}
|
||||
void AstSampleQueueDType::dumpSmall(std::ostream& str) const {
|
||||
@@ -2016,13 +2078,14 @@ void AstUnsizedArrayDType::dumpSmall(std::ostream& str) const {
|
||||
str << "[]";
|
||||
}
|
||||
bool AstUnsizedArrayDType::same(const AstNode* samep) const {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
const AstUnsizedArrayDType* const asamep = VN_DBG_AS(samep, UnsizedArrayDType);
|
||||
if (!asamep->subDTypep()) return false;
|
||||
return (subDTypep() == asamep->subDTypep());
|
||||
}
|
||||
bool AstUnsizedArrayDType::similarDType(const AstNodeDType* samep) const {
|
||||
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
return type() == samep->type() && asamep->subDTypep()
|
||||
if (type() != samep->type()) return false;
|
||||
const AstUnsizedArrayDType* const asamep = VN_DBG_AS(samep, UnsizedArrayDType);
|
||||
return asamep->subDTypep()
|
||||
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
|
||||
}
|
||||
void AstEmptyQueueDType::dumpSmall(std::ostream& str) const {
|
||||
@@ -2040,7 +2103,7 @@ void AstStreamDType::dumpSmall(std::ostream& str) const {
|
||||
void AstVarScope::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (isTrace()) str << " [T]";
|
||||
if (scopep()) str << " [scopep=" << reinterpret_cast<const void*>(scopep()) << "]";
|
||||
if (scopep()) str << " [scopep=" << nodeAddr(scopep()) << "]";
|
||||
if (varp()) {
|
||||
str << " -> ";
|
||||
varp()->dump(str);
|
||||
@@ -2049,7 +2112,7 @@ void AstVarScope::dump(std::ostream& str) const {
|
||||
}
|
||||
}
|
||||
bool AstVarScope::same(const AstNode* samep) const {
|
||||
const AstVarScope* const asamep = static_cast<const AstVarScope*>(samep);
|
||||
const AstVarScope* const asamep = VN_DBG_AS(samep, VarScope);
|
||||
return varp()->same(asamep->varp()) && scopep()->same(asamep->scopep());
|
||||
}
|
||||
void AstNodeVarRef::dump(std::ostream& str) const {
|
||||
@@ -2083,9 +2146,7 @@ const char* AstVarRef::broken() const {
|
||||
BROKEN_RTN(!varp());
|
||||
return AstNodeVarRef::broken();
|
||||
}
|
||||
bool AstVarRef::same(const AstNode* samep) const {
|
||||
return same(static_cast<const AstVarRef*>(samep));
|
||||
}
|
||||
bool AstVarRef::same(const AstNode* samep) const { return same(VN_DBG_AS(samep, VarRef)); }
|
||||
int AstVarRef::instrCount() const {
|
||||
// Account for the target of hard-coded method calls as just an address computation
|
||||
if (const AstCMethodHard* const callp = VN_CAST(backp(), CMethodHard)) {
|
||||
@@ -2104,8 +2165,14 @@ void AstVar::dump(std::ostream& str) const {
|
||||
if (isPulldown()) str << " [PULLDOWN]";
|
||||
if (isUsedClock()) str << " [CLK]";
|
||||
if (isSigPublic()) str << " [P]";
|
||||
if (isInternal()) str << " [INTERNAL]";
|
||||
if (isLatched()) str << " [LATCHED]";
|
||||
if (isUsedLoopIdx()) str << " [LOOP]";
|
||||
if (isRandC()) {
|
||||
str << " [RANDC]";
|
||||
} else if (isRand()) {
|
||||
str << " [RAND]";
|
||||
}
|
||||
if (noReset()) str << " [!RST]";
|
||||
if (attrIsolateAssign()) str << " [aISO]";
|
||||
if (attrFileDescr()) str << " [aFD]";
|
||||
@@ -2120,17 +2187,17 @@ void AstVar::dump(std::ostream& str) const {
|
||||
str << " " << varType();
|
||||
}
|
||||
bool AstVar::same(const AstNode* samep) const {
|
||||
const AstVar* const asamep = static_cast<const AstVar*>(samep);
|
||||
const AstVar* const asamep = VN_DBG_AS(samep, Var);
|
||||
return name() == asamep->name() && varType() == asamep->varType();
|
||||
}
|
||||
void AstScope::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " [abovep=" << reinterpret_cast<const void*>(aboveScopep()) << "]";
|
||||
str << " [cellp=" << reinterpret_cast<const void*>(aboveCellp()) << "]";
|
||||
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
|
||||
str << " [abovep=" << nodeAddr(aboveScopep()) << "]";
|
||||
str << " [cellp=" << nodeAddr(aboveCellp()) << "]";
|
||||
str << " [modp=" << nodeAddr(modp()) << "]";
|
||||
}
|
||||
bool AstScope::same(const AstNode* samep) const {
|
||||
const AstScope* const asamep = static_cast<const AstScope*>(samep);
|
||||
const AstScope* const asamep = VN_DBG_AS(samep, Scope);
|
||||
return name() == asamep->name()
|
||||
&& ((!aboveScopep() && !asamep->aboveScopep())
|
||||
|| (aboveScopep() && asamep->aboveScopep()
|
||||
@@ -2218,6 +2285,31 @@ void AstNodeFTask::dump(std::ostream& str) const {
|
||||
if (taskPublic()) str << " [PUBLIC]";
|
||||
if ((dpiImport() || dpiExport()) && cname() != name()) str << " [c=" << cname() << "]";
|
||||
}
|
||||
bool AstNodeFTask::isPure() {
|
||||
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
||||
return m_purity.get();
|
||||
}
|
||||
const char* AstNodeFTask::broken() const {
|
||||
BROKEN_RTN(m_purity.isCached() && m_purity.get() != getPurityRecurse());
|
||||
return nullptr;
|
||||
}
|
||||
bool AstNodeFTask::getPurityRecurse() const {
|
||||
if (this->dpiImport()) return this->dpiPure();
|
||||
// Check the list of statements if it contains any impure statement
|
||||
// or any write reference to a variable that isn't an automatic function local.
|
||||
for (AstNode* stmtp = this->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (const AstVar* const varp = VN_CAST(stmtp, Var)) {
|
||||
if (varp->isInoutish() || varp->isRef()) return false;
|
||||
}
|
||||
if (!stmtp->isPure()) return false;
|
||||
if (stmtp->exists([](const AstNodeVarRef* const varrefp) {
|
||||
return (!varrefp->varp()->isFuncLocal() || varrefp->varp()->lifetime().isStatic())
|
||||
&& varrefp->access().isWriteOrRW();
|
||||
}))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void AstNodeBlock::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (unnamed()) str << " [UNNAMED]";
|
||||
@@ -2227,6 +2319,7 @@ void AstBegin::dump(std::ostream& str) const {
|
||||
if (generate()) str << " [GEN]";
|
||||
if (genforp()) str << " [GENFOR]";
|
||||
if (implied()) str << " [IMPLIED]";
|
||||
if (needProcess()) str << " [NPRC]";
|
||||
}
|
||||
void AstCoverDecl::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
@@ -2329,6 +2422,7 @@ int AstCMethodHard::instrCount() const {
|
||||
void AstCMethodHard::setPurity() {
|
||||
static const std::map<std::string, bool> isPureMethod{{"andNot", false},
|
||||
{"any", true},
|
||||
{"anyTriggered", false},
|
||||
{"assign", false},
|
||||
{"at", true},
|
||||
{"atBack", true},
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
|
||||
template <class T_Node, class T_Data, int T_UserN>
|
||||
class AstUserAllocatorBase VL_NOT_FINAL {
|
||||
static_assert(1 <= T_UserN && T_UserN <= 5, "Wrong user pointer number");
|
||||
static_assert(1 <= T_UserN && T_UserN <= 4, "Wrong user pointer number");
|
||||
static_assert(std::is_base_of<AstNode, T_Node>::value, "T_Node must be an AstNode type");
|
||||
|
||||
private:
|
||||
std::vector<T_Data*> m_allocated;
|
||||
std::deque<T_Data> m_allocated;
|
||||
|
||||
T_Data* getUserp(const T_Node* nodep) const {
|
||||
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
||||
@@ -45,11 +45,8 @@ private:
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||
const VNUser user = nodep->user3u();
|
||||
return user.to<T_Data*>();
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||
const VNUser user = nodep->user4u();
|
||||
return user.to<T_Data*>();
|
||||
} else {
|
||||
const VNUser user = nodep->user5u();
|
||||
const VNUser user = nodep->user4u();
|
||||
return user.to<T_Data*>();
|
||||
}
|
||||
}
|
||||
@@ -61,10 +58,8 @@ private:
|
||||
nodep->user2u(VNUser{userp});
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||
nodep->user3u(VNUser{userp});
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||
nodep->user4u(VNUser{userp});
|
||||
} else {
|
||||
nodep->user5u(VNUser{userp});
|
||||
nodep->user4u(VNUser{userp});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,18 +71,11 @@ protected:
|
||||
VNUser2InUse::check();
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||
VNUser3InUse::check();
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 4) {
|
||||
VNUser4InUse::check();
|
||||
} else {
|
||||
VNUser5InUse::check();
|
||||
VNUser4InUse::check();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~AstUserAllocatorBase() {
|
||||
// Delete all allocated data structures
|
||||
for (T_Data* const p : m_allocated) { delete p; }
|
||||
}
|
||||
|
||||
VL_UNCOPYABLE(AstUserAllocatorBase);
|
||||
|
||||
public:
|
||||
@@ -96,8 +84,8 @@ public:
|
||||
T_Data& operator()(T_Node* nodep, Args&&... args) {
|
||||
T_Data* userp = getUserp(nodep);
|
||||
if (!userp) {
|
||||
userp = new T_Data{std::forward<Args>(args)...};
|
||||
m_allocated.push_back(userp);
|
||||
m_allocated.emplace_back(std::forward<Args>(args)...);
|
||||
userp = &m_allocated.back();
|
||||
setUserp(nodep, userp);
|
||||
}
|
||||
return *userp;
|
||||
@@ -112,6 +100,8 @@ public:
|
||||
|
||||
// Get a pointer to the user data if exists, otherwise nullptr
|
||||
T_Data* tryGet(const T_Node* nodep) { return getUserp(nodep); }
|
||||
|
||||
void clear() { m_allocated.clear(); }
|
||||
};
|
||||
|
||||
// User pointer allocator classes. T_Node is the type of node the allocator should be applied to
|
||||
@@ -125,7 +115,5 @@ template <class T_Node, class T_Data>
|
||||
class AstUser3Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 3> {};
|
||||
template <class T_Node, class T_Data>
|
||||
class AstUser4Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 4> {};
|
||||
template <class T_Node, class T_Data>
|
||||
class AstUser5Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 5> {};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-7
@@ -26,16 +26,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Begin.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Begin final {
|
||||
public:
|
||||
static void debeginAll(AstNetlist* nodep);
|
||||
static void debeginAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-7
@@ -23,16 +23,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Branch.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
|
||||
+3
-1
@@ -20,6 +20,8 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
@@ -27,7 +29,7 @@ class AstNetlist;
|
||||
class V3Branch final {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
static void branchAll(AstNetlist* nodep);
|
||||
static void branchAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-9
@@ -22,18 +22,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstMT.h"
|
||||
|
||||
#include "V3Broken.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
|
||||
#include "V3AstConstOnly.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
+1
-4
@@ -24,15 +24,12 @@
|
||||
// This transformation honors outputSplitCFuncs.
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3CCtors.h"
|
||||
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
+4
-2
@@ -20,14 +20,16 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CCtors final {
|
||||
public:
|
||||
static void cctorsAll();
|
||||
static void cctorsAll() VL_MT_DISABLED;
|
||||
|
||||
private:
|
||||
static void evalAsserts();
|
||||
static void evalAsserts() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-9
@@ -22,18 +22,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3CUse.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3FileLine.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
|
||||
+3
-1
@@ -20,11 +20,13 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CUse final {
|
||||
public:
|
||||
static void cUseAll();
|
||||
static void cUseAll() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+7
-12
@@ -34,17 +34,12 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Case.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
|
||||
@@ -362,10 +357,10 @@ private:
|
||||
|
||||
// Alternate scheme if we ever do multiple bits at a time:
|
||||
// V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
|
||||
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
|
||||
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTreePure(false),
|
||||
// new AstConst(cexprp->fileline(), nummask));
|
||||
AstNodeExpr* const and1p
|
||||
= new AstSel{cexprp->fileline(), cexprp->cloneTree(false), msb, 1};
|
||||
= new AstSel{cexprp->fileline(), cexprp->cloneTreePure(false), msb, 1};
|
||||
AstNodeExpr* const eqp
|
||||
= new AstNeq{cexprp->fileline(), new AstConst{cexprp->fileline(), 0}, and1p};
|
||||
AstIf* const ifp = new AstIf{cexprp->fileline(), eqp, tree1p, tree0p};
|
||||
@@ -450,7 +445,7 @@ private:
|
||||
V3Number numval{itemp, iconstp->width()};
|
||||
numval.opBitsOne(iconstp->num());
|
||||
AstNodeExpr* const and1p
|
||||
= new AstAnd{itemp->fileline(), cexprp->cloneTree(false),
|
||||
= new AstAnd{itemp->fileline(), cexprp->cloneTreePure(false),
|
||||
new AstConst{itemp->fileline(), nummask}};
|
||||
AstNodeExpr* const and2p = new AstAnd{
|
||||
itemp->fileline(), new AstConst{itemp->fileline(), numval},
|
||||
@@ -460,7 +455,7 @@ private:
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
} else {
|
||||
// Not a caseX mask, we can build CASEEQ(cexpr icond)
|
||||
AstNodeExpr* const and1p = cexprp->cloneTree(false);
|
||||
AstNodeExpr* const and1p = cexprp->cloneTreePure(false);
|
||||
AstNodeExpr* const and2p = icondp;
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
}
|
||||
@@ -502,7 +497,7 @@ private:
|
||||
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
|
||||
if (depth == 1) { // First group or starting new group
|
||||
itemnextp = nullptr;
|
||||
AstIf* const newp = new AstIf{itemp->fileline(), ifexprp->cloneTree(true)};
|
||||
AstIf* const newp = new AstIf{itemp->fileline(), ifexprp->cloneTreePure(true)};
|
||||
if (groupnextp) {
|
||||
groupnextp->addElsesp(newp);
|
||||
} else {
|
||||
@@ -512,7 +507,7 @@ private:
|
||||
} else { // Continue group, modify if condition to OR in this new condition
|
||||
AstNodeExpr* const condp = groupnextp->condp()->unlinkFrBack();
|
||||
groupnextp->condp(
|
||||
new AstOr{ifexprp->fileline(), condp, ifexprp->cloneTree(true)});
|
||||
new AstOr{ifexprp->fileline(), condp, ifexprp->cloneTreePure(true)});
|
||||
}
|
||||
}
|
||||
{ // Make the new lower IF and attach in the tree
|
||||
|
||||
+4
-2
@@ -20,6 +20,8 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
class AstNodeCase;
|
||||
|
||||
@@ -27,8 +29,8 @@ class AstNodeCase;
|
||||
|
||||
class V3Case final {
|
||||
public:
|
||||
static void caseAll(AstNetlist* nodep);
|
||||
static void caseLint(AstNodeCase* nodep);
|
||||
static void caseAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
static void caseLint(AstNodeCase* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+13
-10
@@ -37,16 +37,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Cast.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
@@ -56,7 +50,7 @@ class CastVisitor final : public VNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNode::user() // bool. Indicates node is of known size
|
||||
// AstNode::user1() // bool. Indicates node is of known size
|
||||
const VNUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
@@ -64,12 +58,12 @@ private:
|
||||
// METHODS
|
||||
|
||||
void insertCast(AstNodeExpr* nodep, int needsize) { // We'll insert ABOVE passed node
|
||||
UINFO(4, " NeedCast " << nodep << endl);
|
||||
VNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
//
|
||||
AstCCast* const castp
|
||||
= new AstCCast{nodep->fileline(), nodep, needsize, nodep->widthMin()};
|
||||
UINFO(4, " MadeCast " << static_cast<void*>(castp) << " for " << nodep << endl);
|
||||
relinkHandle.relink(castp);
|
||||
// if (debug() > 8) castp->dumpTree("- castins: ");
|
||||
//
|
||||
@@ -168,6 +162,15 @@ private:
|
||||
ensureLower32Cast(nodep);
|
||||
nodep->user1(1);
|
||||
}
|
||||
void visit(AstConsPackMember* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (VN_IS(nodep->rhsp()->dtypep()->skipRefp(), BasicDType)) ensureCast(nodep->rhsp());
|
||||
nodep->user1(1);
|
||||
}
|
||||
void visit(AstExprStmt* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(1);
|
||||
}
|
||||
void visit(AstNegate* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
@@ -187,7 +190,7 @@ private:
|
||||
&& !VN_IS(backp, ArraySel) && !VN_IS(backp, StructSel) && !VN_IS(backp, RedXor)
|
||||
&& (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec()
|
||||
&& !nodep->varp()->basicp()->isForkSync()
|
||||
&& !nodep->varp()->basicp()->isProcessRef())
|
||||
&& !nodep->varp()->basicp()->isProcessRef() && !nodep->varp()->basicp()->isEvent())
|
||||
&& backp->width() && castSize(nodep) != castSize(nodep->varp())) {
|
||||
// Cast vars to IData first, else below has upper bits wrongly set
|
||||
// CData x=3; out = (QData)(x<<30);
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Cast final {
|
||||
public:
|
||||
static void castAll(AstNetlist* nodep);
|
||||
static void castAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+10
-17
@@ -20,13 +20,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Class.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
@@ -121,17 +118,17 @@ private:
|
||||
void visit(AstVar* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_packageScopep) {
|
||||
if (m_ftaskp && m_ftaskp->lifetime().isStatic()) {
|
||||
if (m_ftaskp && m_ftaskp->isStatic()) {
|
||||
// Move later, or we wouldn't keep iterating the class
|
||||
// We're really moving the VarScope but we might not
|
||||
// have a pointer to it yet
|
||||
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
|
||||
m_toScopeMoves.emplace_back(nodep, m_packageScopep);
|
||||
}
|
||||
if (!m_ftaskp && nodep->lifetime().isStatic()) {
|
||||
m_toPackageMoves.emplace_back(std::make_pair(nodep, m_classPackagep));
|
||||
m_toPackageMoves.emplace_back(nodep, m_classPackagep);
|
||||
// We're really moving the VarScope but we might not
|
||||
// have a pointer to it yet
|
||||
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
|
||||
m_toScopeMoves.emplace_back(nodep, m_packageScopep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,8 +143,8 @@ private:
|
||||
{
|
||||
m_ftaskp = nodep;
|
||||
iterateChildren(nodep);
|
||||
if (m_packageScopep && nodep->lifetime().isStatic()) {
|
||||
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
|
||||
if (m_packageScopep && nodep->isStatic()) {
|
||||
m_toScopeMoves.emplace_back(nodep, m_packageScopep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,7 +153,7 @@ private:
|
||||
// Don't move now, or wouldn't keep iterating the class
|
||||
// TODO move function statics only
|
||||
// if (m_classScopep) {
|
||||
// m_toScopeMoves.push_back(std::make_pair(nodep, m_classScopep));
|
||||
// m_toScopeMoves.emplace_back(nodep, m_classScopep);
|
||||
//}
|
||||
}
|
||||
void visit(AstCoverDecl* nodep) override {
|
||||
@@ -167,16 +164,12 @@ private:
|
||||
void visit(AstInitial* nodep) override {
|
||||
// But not AstInitialAutomatic, which remains under the class
|
||||
iterateChildren(nodep);
|
||||
if (m_packageScopep) {
|
||||
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
|
||||
}
|
||||
if (m_packageScopep) { m_toScopeMoves.emplace_back(nodep, m_packageScopep); }
|
||||
}
|
||||
void visit(AstInitialStatic* nodep) override {
|
||||
// But not AstInitialAutomatic, which remains under the class
|
||||
iterateChildren(nodep);
|
||||
if (m_packageScopep) {
|
||||
m_toScopeMoves.emplace_back(std::make_pair(nodep, m_packageScopep));
|
||||
}
|
||||
if (m_packageScopep) { m_toScopeMoves.emplace_back(nodep, m_packageScopep); }
|
||||
}
|
||||
|
||||
void setStructModulep(AstNodeUOrStructDType* const dtypep) {
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Class final {
|
||||
public:
|
||||
static void classAll(AstNetlist* nodep);
|
||||
static void classAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-7
@@ -23,16 +23,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Clean.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Clean final {
|
||||
public:
|
||||
static void cleanAll(AstNetlist* nodep);
|
||||
static void cleanAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-6
@@ -27,17 +27,12 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Clock.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Sched.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
//######################################################################
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Clock final {
|
||||
public:
|
||||
static void clockAll(AstNetlist* nodep);
|
||||
static void clockAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-4
@@ -19,15 +19,12 @@
|
||||
// Also drop empty CFuncs
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Combine.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3AstUserAllocator.h"
|
||||
#include "V3DupFinder.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
+3
-1
@@ -20,13 +20,15 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Combine final {
|
||||
public:
|
||||
static void combineAll(AstNetlist* nodep);
|
||||
static void combineAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+2
-5
@@ -20,14 +20,11 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Common.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
@@ -116,7 +113,7 @@ static void makeToStringMiddle(AstClass* nodep) {
|
||||
std::string comma;
|
||||
for (AstNode* itemp = nodep->membersp(); itemp; itemp = itemp->nextp()) {
|
||||
if (const auto* const varp = VN_CAST(itemp, Var)) {
|
||||
if (!varp->isParam()) {
|
||||
if (!varp->isParam() && !varp->isInternal()) {
|
||||
string stmt = "out += \"";
|
||||
stmt += comma;
|
||||
comma = ", ";
|
||||
|
||||
+3
-1
@@ -20,11 +20,13 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Common final {
|
||||
public:
|
||||
static void commonAll();
|
||||
static void commonAll() VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+11
-17
@@ -14,17 +14,13 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstMT.h"
|
||||
|
||||
#include "V3Config.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3String.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
@@ -303,8 +299,8 @@ public:
|
||||
m_ignLines.insert(V3ConfigIgnoresLine{code, lineno, on});
|
||||
m_lastIgnore.it = m_ignLines.begin();
|
||||
}
|
||||
void addWaiver(V3ErrorCode code, const string& match) {
|
||||
m_waivers.push_back(std::make_pair(code, match));
|
||||
void addIgnoreMatch(V3ErrorCode code, const string& match) {
|
||||
m_waivers.emplace_back(code, match);
|
||||
}
|
||||
|
||||
void applyBlock(AstNodeBlock* nodep) {
|
||||
@@ -404,12 +400,10 @@ public:
|
||||
|
||||
bool getEntryMatch(const V3ConfigScopeTraceEntry* entp, const string& scopepart) {
|
||||
// Return if a entry matches the scopepart, with memoization
|
||||
const auto& key = V3ConfigScopeTraceEntryMatch{entp, scopepart};
|
||||
const auto& it = m_matchCache.find(key);
|
||||
if (it != m_matchCache.end()) return it->second; // Cached
|
||||
const bool matched = VString::wildmatch(scopepart, entp->m_scope);
|
||||
m_matchCache.emplace(key, matched);
|
||||
return matched;
|
||||
const V3ConfigScopeTraceEntryMatch key{entp, scopepart};
|
||||
const auto pair = m_matchCache.emplace(key, false);
|
||||
if (pair.second) pair.first->second = VString::wildmatch(scopepart, entp->m_scope);
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
bool getScopeTraceOn(const string& scope) {
|
||||
@@ -518,6 +512,10 @@ void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int
|
||||
}
|
||||
}
|
||||
|
||||
void V3Config::addIgnoreMatch(V3ErrorCode code, const string& filename, const string& match) {
|
||||
V3ConfigResolver::s().files().at(filename).addIgnoreMatch(code, match);
|
||||
}
|
||||
|
||||
void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) {
|
||||
if (ftask.empty()) {
|
||||
V3ConfigResolver::s().modules().at(module).setInline(on);
|
||||
@@ -590,10 +588,6 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas
|
||||
}
|
||||
}
|
||||
|
||||
void V3Config::addWaiver(V3ErrorCode code, const string& filename, const string& message) {
|
||||
V3ConfigResolver::s().files().at(filename).addWaiver(code, message);
|
||||
}
|
||||
|
||||
void V3Config::applyCase(AstCase* nodep) {
|
||||
const string& filename = nodep->fileline()->filename();
|
||||
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filename);
|
||||
|
||||
+1
-1
@@ -34,6 +34,7 @@ public:
|
||||
static void addCoverageBlockOff(const string& file, int lineno);
|
||||
static void addCoverageBlockOff(const string& module, const string& blockname);
|
||||
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
|
||||
static void addIgnoreMatch(V3ErrorCode code, const string& filename, const string& match);
|
||||
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
|
||||
static void addModulePragma(const string& module, VPragmaType pragma);
|
||||
static void addProfileData(FileLine* fl, const string& model, const string& key,
|
||||
@@ -41,7 +42,6 @@ public:
|
||||
static void addScopeTraceOn(bool on, const string& scope, int levels);
|
||||
static void addVarAttr(FileLine* fl, const string& module, const string& ftask,
|
||||
const string& signal, VAttrType type, AstSenTree* nodep);
|
||||
static void addWaiver(V3ErrorCode code, const string& filename, const string& message);
|
||||
|
||||
static void applyCase(AstCase* nodep);
|
||||
static void applyCoverageBlock(AstNodeModule* modulep, AstBegin* nodep);
|
||||
|
||||
+198
-146
@@ -20,6 +20,8 @@
|
||||
// If operands are constant, replace this node with constant.
|
||||
//*************************************************************************
|
||||
|
||||
#define VL_MT_DISABLED_CODE_UNIT 1
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
@@ -671,7 +673,7 @@ public:
|
||||
// Reduction ops are transformed in the same way.
|
||||
// &{v[0], v[1]} => 2'b11 == (2'b11 & v)
|
||||
static AstNodeExpr* simplify(AstNodeExpr* nodep, int resultWidth, unsigned externalOps,
|
||||
VDouble0& reduction) {
|
||||
VDouble0& reduction, VNDeleter& deleterr) {
|
||||
UASSERT_OBJ(1 <= resultWidth && resultWidth <= 64, nodep, "resultWidth out of range");
|
||||
|
||||
// Walk tree, gathering all terms referenced in expression
|
||||
@@ -714,7 +716,7 @@ public:
|
||||
}
|
||||
// Set width and widthMin precisely
|
||||
resultp->dtypeChgWidth(resultWidth, 1);
|
||||
for (AstNode* const termp : termps) termp->deleteTree();
|
||||
for (AstNode* const termp : termps) deleterr.pushDeletep(termp);
|
||||
return resultp;
|
||||
}
|
||||
const ResultTerm result = v->getResultTerm();
|
||||
@@ -790,7 +792,7 @@ public:
|
||||
|
||||
// Only substitute the result if beneficial as determined by operation count
|
||||
if (visitor.m_ops <= resultOps) {
|
||||
for (AstNode* const termp : termps) termp->deleteTree();
|
||||
for (AstNode* const termp : termps) deleterr.pushDeletep(termp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -898,6 +900,7 @@ private:
|
||||
bool m_doNConst = false; // Enable non-constant-child simplifications
|
||||
bool m_doV = false; // Verilog, not C++ conversion
|
||||
bool m_doGenerate = false; // Postpone width checking inside generate
|
||||
bool m_convertLogicToBit = false; // Convert logical operators to bitwise
|
||||
bool m_hasJumpDelay = false; // JumpGo or Delay under this while
|
||||
bool m_underRecFunc = false; // Under a recursive function
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
@@ -908,6 +911,7 @@ private:
|
||||
const bool m_globalPass; // ConstVisitor invoked as a global pass
|
||||
static uint32_t s_globalPassNum; // Counts number of times ConstVisitor invoked as global pass
|
||||
V3UniqueNames m_concswapNames; // For generating unique temporary variable names
|
||||
std::map<const AstNode*, bool> m_containsMemberAccess; // Caches results of matchBiopToBitwise
|
||||
|
||||
// METHODS
|
||||
|
||||
@@ -995,7 +999,7 @@ private:
|
||||
}
|
||||
if (ccastp) {
|
||||
andp->replaceWith(ccastp);
|
||||
VL_DO_DANGLING(andp->deleteTree(), andp);
|
||||
VL_DO_DANGLING(pushDeletep(andp), andp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1010,7 +1014,7 @@ private:
|
||||
return (lp && rp && lp->width() == rp->width() && lp->type() == rp->type()
|
||||
&& (operandsSame(lp->lhsp(), rp->lhsp()) || operandsSame(lp->rhsp(), rp->rhsp())));
|
||||
}
|
||||
static bool matchOrAndNot(AstNodeBiop* nodep) {
|
||||
bool matchOrAndNot(AstNodeBiop* nodep) {
|
||||
// AstOr{$a, AstAnd{AstNot{$b}, $c}} if $a.width1, $a==$b => AstOr{$a,$c}
|
||||
// Someday we'll sort the biops completely and this can be simplified
|
||||
// This often results from our simplified clock generation:
|
||||
@@ -1041,7 +1045,7 @@ private:
|
||||
if (!operandsSame(ap, bp)) return false;
|
||||
// Do it
|
||||
cp->unlinkFrBack();
|
||||
VL_DO_DANGLING(andp->unlinkFrBack()->deleteTree(), andp);
|
||||
VL_DO_DANGLING(pushDeletep(andp->unlinkFrBack()), andp);
|
||||
VL_DANGLING(notp);
|
||||
// Replace whichever branch is now dangling
|
||||
if (nodep->rhsp()) {
|
||||
@@ -1072,7 +1076,7 @@ private:
|
||||
newp->thenp()->dtypeFrom(nodep); // As And might have been to change widths
|
||||
newp->elsep()->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
}
|
||||
bool matchMaskedOr(AstAnd* nodep) {
|
||||
@@ -1103,15 +1107,15 @@ private:
|
||||
if (orLIsRedundant && orRIsRedundant) {
|
||||
nodep->replaceWith(
|
||||
new AstConst{nodep->fileline(), AstConst::DTyped{}, nodep->dtypep()});
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
} else if (orLIsRedundant) {
|
||||
orp->replaceWith(orp->rhsp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(orp->deleteTree(), orp);
|
||||
VL_DO_DANGLING(pushDeletep(orp), orp);
|
||||
return false; // input node is still valid, keep going
|
||||
} else if (orRIsRedundant) {
|
||||
orp->replaceWith(orp->lhsp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(orp->deleteTree(), orp);
|
||||
VL_DO_DANGLING(pushDeletep(orp), orp);
|
||||
return false; // input node is still valid, keep going
|
||||
} else {
|
||||
return false;
|
||||
@@ -1129,7 +1133,7 @@ private:
|
||||
rhsp->unlinkFrBack();
|
||||
nodep->replaceWith(rhsp);
|
||||
rhsp->dtypeFrom(nodep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1173,15 +1177,17 @@ private:
|
||||
const AstAnd* const andp = VN_CAST(nodep, And);
|
||||
const int width = nodep->width();
|
||||
if (andp && isConst(andp->lhsp(), 1)) { // 1 & BitOpTree
|
||||
newp = ConstBitOpTreeVisitor::simplify(andp->rhsp(), width, 1, m_statBitOpReduction);
|
||||
newp = ConstBitOpTreeVisitor::simplify(andp->rhsp(), width, 1, m_statBitOpReduction,
|
||||
deleter());
|
||||
} else { // BitOpTree
|
||||
newp = ConstBitOpTreeVisitor::simplify(nodep, width, 0, m_statBitOpReduction);
|
||||
newp = ConstBitOpTreeVisitor::simplify(nodep, width, 0, m_statBitOpReduction,
|
||||
deleter());
|
||||
}
|
||||
|
||||
if (newp) {
|
||||
UINFO(4, "Transformed leaf of bit tree to " << newp << std::endl);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
if (debug() >= 9) { // LCOV_EXCL_START
|
||||
@@ -1217,13 +1223,13 @@ private:
|
||||
bool operandHugeShiftL(const AstNodeBiop* nodep) {
|
||||
return (VN_IS(nodep->rhsp(), Const) && !VN_AS(nodep->rhsp(), Const)->num().isFourState()
|
||||
&& (VN_AS(nodep->rhsp(), Const)->toUInt() >= static_cast<uint32_t>(nodep->width()))
|
||||
&& isTPure(nodep->lhsp()));
|
||||
&& nodep->lhsp()->isPure());
|
||||
}
|
||||
bool operandHugeShiftR(const AstNodeBiop* nodep) {
|
||||
return (VN_IS(nodep->rhsp(), Const) && !VN_AS(nodep->rhsp(), Const)->num().isFourState()
|
||||
&& (VN_AS(nodep->rhsp(), Const)->toUInt()
|
||||
>= static_cast<uint32_t>(nodep->lhsp()->width()))
|
||||
&& isTPure(nodep->lhsp()));
|
||||
&& nodep->lhsp()->isPure());
|
||||
}
|
||||
bool operandIsTwo(const AstNode* nodep) {
|
||||
return (VN_IS(nodep, Const) && !VN_AS(nodep, Const)->num().isFourState()
|
||||
@@ -1345,14 +1351,14 @@ private:
|
||||
//
|
||||
if (debug() >= 9) nodep->dumpTree("- BI(EXTEND)-in: ");
|
||||
smallerp->unlinkFrBack();
|
||||
VL_DO_DANGLING(extendp->unlinkFrBack()->deleteTree(), extendp); // aka nodep->lhsp.
|
||||
VL_DO_DANGLING(pushDeletep(extendp->unlinkFrBack()), extendp); // aka nodep->lhsp.
|
||||
nodep->rhsp(smallerp);
|
||||
|
||||
constp->unlinkFrBack();
|
||||
V3Number num{constp, subsize};
|
||||
num.opAssign(constp->num());
|
||||
nodep->lhsp(new AstConst{constp->fileline(), num});
|
||||
VL_DO_DANGLING(constp->deleteTree(), constp);
|
||||
VL_DO_DANGLING(pushDeletep(constp), constp);
|
||||
if (debug() >= 9) nodep->dumpTree("- BI(EXTEND)-ou: ");
|
||||
return true;
|
||||
}
|
||||
@@ -1370,21 +1376,6 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
AstNode* afterComment(AstNode* nodep) {
|
||||
// Ignore comments, such as to determine if a AstIf is empty.
|
||||
// nodep may be null, if so return null.
|
||||
while (nodep && VN_IS(nodep, Comment)) { nodep = nodep->nextp(); }
|
||||
return nodep;
|
||||
}
|
||||
|
||||
bool isTPure(AstNode* nodep) {
|
||||
// Pure checks - if this node and all nodes under it are free of
|
||||
// side effects can do this optimization
|
||||
// Eventually we'll recurse through tree when unknown, memoizing results so far,
|
||||
// but for now can disable en masse until V3Purify takes effect.
|
||||
return m_doShort || VN_IS(nodep, VarRef) || VN_IS(nodep, Const);
|
||||
}
|
||||
|
||||
// Extraction checks
|
||||
bool warnSelect(AstSel* nodep) {
|
||||
if (m_doGenerate) {
|
||||
@@ -1443,7 +1434,7 @@ private:
|
||||
// Avoid comparing widthMin's, which results in lost optimization attempts
|
||||
// If cleanup sameGateTree to be smarter, this can be restored.
|
||||
// return node1p->sameGateTree(node2p);
|
||||
return node1p->same(node2p);
|
||||
return node1p->isSame(node2p);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -1465,7 +1456,7 @@ private:
|
||||
const AstNodeIf* const lowerIfp = VN_CAST(nodep->thensp(), NodeIf);
|
||||
if (!lowerIfp || lowerIfp->nextp()) return false;
|
||||
if (nodep->type() != lowerIfp->type()) return false;
|
||||
if (afterComment(lowerIfp->elsesp())) return false;
|
||||
if (AstNode::afterCommentp(lowerIfp->elsesp())) return false;
|
||||
return true;
|
||||
}
|
||||
bool ifConcatMergeableBiop(const AstNode* nodep) {
|
||||
@@ -1494,13 +1485,13 @@ private:
|
||||
const AstSel* rselp = VN_CAST(rhsp, Sel);
|
||||
// a[i:0] a
|
||||
if (lselp && !rselp && rhsp->sameGateTree(lselp->fromp()))
|
||||
rselp = new AstSel{rhsp->fileline(), rhsp->cloneTree(false), 0, rhsp->width()};
|
||||
rselp = new AstSel{rhsp->fileline(), rhsp->cloneTreePure(false), 0, rhsp->width()};
|
||||
// a[i:j] {a[j-1:k], b}
|
||||
if (lselp && !rselp && VN_IS(rhsp, Concat))
|
||||
return ifMergeAdjacent(lhsp, VN_CAST(rhsp, Concat)->lhsp());
|
||||
// a a[msb:j]
|
||||
if (rselp && !lselp && lhsp->sameGateTree(rselp->fromp()))
|
||||
lselp = new AstSel{lhsp->fileline(), lhsp->cloneTree(false), 0, lhsp->width()};
|
||||
lselp = new AstSel{lhsp->fileline(), lhsp->cloneTreePure(false), 0, lhsp->width()};
|
||||
// {b, a[j:k]} a[k-1:i]
|
||||
if (rselp && !lselp && VN_IS(lhsp, Concat))
|
||||
return ifMergeAdjacent(VN_CAST(lhsp, Concat)->rhsp(), rhsp);
|
||||
@@ -1563,7 +1554,7 @@ private:
|
||||
if (debug() > 5) oldp->dumpTree("- const_old: ");
|
||||
if (debug() > 5) newp->dumpTree("- _new: ");
|
||||
oldp->replaceWith(newp);
|
||||
VL_DO_DANGLING(oldp->deleteTree(), oldp);
|
||||
VL_DO_DANGLING(pushDeletep(oldp), oldp);
|
||||
}
|
||||
void replaceNum(AstNode* nodep, uint32_t val) {
|
||||
V3Number num{nodep, nodep->width(), val};
|
||||
@@ -1587,14 +1578,14 @@ private:
|
||||
// For example, "0 * n" -> 0 if n has no side effects
|
||||
// Else strength reduce it to 0 & n.
|
||||
// If ever change the operation note AstAnd rule specially ignores this created pattern
|
||||
if (isTPure(checkp)) {
|
||||
if (checkp->isPure()) {
|
||||
VL_DO_DANGLING(replaceNum(nodep, 0), nodep);
|
||||
} else {
|
||||
AstNode* const newp = new AstAnd{nodep->fileline(), new AstConst{nodep->fileline(), 0},
|
||||
checkp->unlinkFrBack()};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
void replaceAllOnes(AstNode* nodep) {
|
||||
@@ -1639,7 +1630,7 @@ private:
|
||||
if (debug() > 5) oldp->dumpTree("- const_old: ");
|
||||
if (debug() > 5) newp->dumpTree("- _new: ");
|
||||
oldp->replaceWith(newp);
|
||||
VL_DO_DANGLING(oldp->deleteTree(), oldp);
|
||||
VL_DO_DANGLING(pushDeletep(oldp), oldp);
|
||||
}
|
||||
//----------------------------------------
|
||||
// Replacement functions.
|
||||
@@ -1652,7 +1643,7 @@ private:
|
||||
// This may adversely affect the operation of the node being replaced.
|
||||
childp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(childp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void replaceWChildBool(AstNode* nodep, AstNodeExpr* childp) {
|
||||
// NODE(..., CHILD(...)) -> REDOR(CHILD(...))
|
||||
@@ -1662,7 +1653,7 @@ private:
|
||||
} else {
|
||||
nodep->replaceWith(new AstRedOr{childp->fileline(), childp});
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
//! Replace a ternary node with its RHS after iterating
|
||||
@@ -1753,16 +1744,16 @@ private:
|
||||
lp->dtypeFrom(nodep);
|
||||
nodep->lhsp(lrp);
|
||||
nodep->rhsp(rrp);
|
||||
VL_DO_DANGLING(rp->deleteTree(), rp);
|
||||
VL_DO_DANGLING(rlp->deleteTree(), rlp);
|
||||
VL_DO_DANGLING(pushDeletep(rp), rp);
|
||||
VL_DO_DANGLING(pushDeletep(rlp), rlp);
|
||||
} else if (operandsSame(lrp, rrp)) {
|
||||
lp->lhsp(nodep);
|
||||
lp->rhsp(rrp);
|
||||
lp->dtypeFrom(nodep);
|
||||
nodep->lhsp(llp);
|
||||
nodep->rhsp(rlp);
|
||||
VL_DO_DANGLING(rp->deleteTree(), rp);
|
||||
VL_DO_DANGLING(lrp->deleteTree(), lrp);
|
||||
VL_DO_DANGLING(pushDeletep(rp), rp);
|
||||
VL_DO_DANGLING(pushDeletep(lrp), lrp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("replaceAndOr on something operandAndOrSame shouldn't have matched");
|
||||
}
|
||||
@@ -1783,8 +1774,8 @@ private:
|
||||
nodep->lhsp(llp);
|
||||
nodep->rhsp(rlp);
|
||||
nodep->dtypep(llp->dtypep()); // dtype of Biop is before shift.
|
||||
VL_DO_DANGLING(rp->deleteTree(), rp);
|
||||
VL_DO_DANGLING(rrp->deleteTree(), rrp);
|
||||
VL_DO_DANGLING(pushDeletep(rp), rp);
|
||||
VL_DO_DANGLING(pushDeletep(rrp), rrp);
|
||||
// nodep->dumpTree("- repShiftSame_new: ");
|
||||
}
|
||||
void replaceConcatSel(AstConcat* nodep) {
|
||||
@@ -1804,18 +1795,18 @@ private:
|
||||
<< endl);
|
||||
|
||||
nodep->replaceWith(newselp);
|
||||
VL_DO_DANGLING(lselp->deleteTree(), lselp);
|
||||
VL_DO_DANGLING(rselp->deleteTree(), rselp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(lselp), lselp);
|
||||
VL_DO_DANGLING(pushDeletep(rselp), rselp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void replaceConcatMerge(AstConcat* nodep) {
|
||||
// {llp OP lrp, rlp OP rrp} => {llp, rlp} OP {lrp, rrp}, where OP = AND/OR/XOR
|
||||
AstNodeBiop* const lp = VN_AS(nodep->lhsp(), NodeBiop);
|
||||
AstNodeBiop* const rp = VN_AS(nodep->rhsp(), NodeBiop);
|
||||
AstNodeExpr* const llp = lp->lhsp()->cloneTree(false);
|
||||
AstNodeExpr* const lrp = lp->rhsp()->cloneTree(false);
|
||||
AstNodeExpr* const rlp = rp->lhsp()->cloneTree(false);
|
||||
AstNodeExpr* const rrp = rp->rhsp()->cloneTree(false);
|
||||
AstNodeExpr* const llp = lp->lhsp()->cloneTreePure(false);
|
||||
AstNodeExpr* const lrp = lp->rhsp()->cloneTreePure(false);
|
||||
AstNodeExpr* const rlp = rp->lhsp()->cloneTreePure(false);
|
||||
AstNodeExpr* const rrp = rp->rhsp()->cloneTreePure(false);
|
||||
if (concatMergeable(lp, rp, 0)) {
|
||||
AstConcat* const newlp = new AstConcat{rlp->fileline(), llp, rlp};
|
||||
AstConcat* const newrp = new AstConcat{rrp->fileline(), lrp, rrp};
|
||||
@@ -1824,9 +1815,9 @@ private:
|
||||
lp->rhsp()->replaceWith(newrp);
|
||||
lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), VSigning::UNSIGNED);
|
||||
UINFO(5, "merged " << nodep << endl);
|
||||
VL_DO_DANGLING(rp->unlinkFrBack()->deleteTree(), rp);
|
||||
VL_DO_DANGLING(pushDeletep(rp->unlinkFrBack()), rp);
|
||||
nodep->replaceWith(lp->unlinkFrBack());
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
iterate(lp->lhsp());
|
||||
iterate(lp->rhsp());
|
||||
} else {
|
||||
@@ -1843,7 +1834,7 @@ private:
|
||||
: static_cast<AstNodeExpr*>(new AstExtend{nodep->fileline(), arg0p}));
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void replacePowShift(AstNodeBiop* nodep) { // Pow or PowS
|
||||
UINFO(5, "POW(2,b)->SHIFTL(1,b) " << nodep << endl);
|
||||
@@ -1853,7 +1844,7 @@ private:
|
||||
newp->dtypeFrom(nodep);
|
||||
newp->lhsp()->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void replaceMulShift(AstMul* nodep) { // Mul, but not MulS as not simple shift
|
||||
UINFO(5, "MUL(2^n,b)->SHIFTL(b,n) " << nodep << endl);
|
||||
@@ -1863,7 +1854,7 @@ private:
|
||||
= new AstShiftL{nodep->fileline(), opp, new AstConst(nodep->fileline(), amount)};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void replaceDivShift(AstDiv* nodep) { // Mul, but not MulS as not simple shift
|
||||
UINFO(5, "DIV(b,2^n)->SHIFTR(b,n) " << nodep << endl);
|
||||
@@ -1873,7 +1864,7 @@ private:
|
||||
= new AstShiftR{nodep->fileline(), opp, new AstConst(nodep->fileline(), amount)};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void replaceModAnd(AstModDiv* nodep) { // Mod, but not ModS as not simple shift
|
||||
UINFO(5, "MOD(b,2^n)->AND(b,2^n-1) " << nodep << endl);
|
||||
@@ -1885,7 +1876,7 @@ private:
|
||||
= new AstAnd{nodep->fileline(), opp, new AstConst{nodep->fileline(), mask}};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void replaceShiftOp(AstNodeBiop* nodep) {
|
||||
UINFO(5, "SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) " << nodep << endl);
|
||||
@@ -1899,7 +1890,7 @@ private:
|
||||
AstNodeBiop* const shift1p = nodep;
|
||||
AstNodeBiop* const shift2p = nodep->cloneTree(true);
|
||||
shift1p->lhsp(ap);
|
||||
shift1p->rhsp(shiftp->cloneTree(true));
|
||||
shift1p->rhsp(shiftp->cloneTreePure(true));
|
||||
shift2p->lhsp(bp);
|
||||
shift2p->rhsp(shiftp);
|
||||
AstNodeBiop* const newp = lhsp;
|
||||
@@ -1922,8 +1913,8 @@ private:
|
||||
const int shift1 = VN_AS(shift1p, Const)->toUInt();
|
||||
const int shift2 = VN_AS(shift2p, Const)->toUInt();
|
||||
const int newshift = shift1 + shift2;
|
||||
VL_DO_DANGLING(shift1p->deleteTree(), shift1p);
|
||||
VL_DO_DANGLING(shift2p->deleteTree(), shift2p);
|
||||
VL_DO_DANGLING(pushDeletep(shift1p), shift1p);
|
||||
VL_DO_DANGLING(pushDeletep(shift2p), shift2p);
|
||||
nodep->lhsp(ap);
|
||||
nodep->rhsp(new AstConst(nodep->fileline(), newshift));
|
||||
iterate(nodep); // Further reduce, either node may have more reductions.
|
||||
@@ -1934,8 +1925,8 @@ private:
|
||||
int shift2 = VN_AS(shift2p, Const)->toUInt();
|
||||
if (VN_IS(nodep, ShiftR)) shift2 = -shift2;
|
||||
const int newshift = shift1 + shift2;
|
||||
VL_DO_DANGLING(shift1p->deleteTree(), shift1p);
|
||||
VL_DO_DANGLING(shift2p->deleteTree(), shift2p);
|
||||
VL_DO_DANGLING(pushDeletep(shift1p), shift1p);
|
||||
VL_DO_DANGLING(pushDeletep(shift2p), shift2p);
|
||||
AstNodeExpr* newp;
|
||||
V3Number mask1{nodep, nodep->width()};
|
||||
V3Number ones{nodep, nodep->width()};
|
||||
@@ -1962,11 +1953,11 @@ private:
|
||||
newp = new AstAnd{nodep->fileline(), newp, new AstConst{nodep->fileline(), mask}};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
// newp->dumpTree("- repShiftShift_new: ");
|
||||
iterate(newp); // Further reduce, either node may have more reductions.
|
||||
}
|
||||
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
|
||||
VL_DO_DANGLING(pushDeletep(lhsp), lhsp);
|
||||
}
|
||||
|
||||
bool replaceAssignMultiSel(AstNodeAssign* nodep) {
|
||||
@@ -2022,8 +2013,8 @@ private:
|
||||
}
|
||||
// pnewp->dumpTree("- conew: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(nextp->unlinkFrBack()->deleteTree(), nextp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nextp->unlinkFrBack()), nextp);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2050,10 +2041,10 @@ private:
|
||||
nodep->v3error("Wire inputs its own output, creating circular logic (wire x=x)");
|
||||
return false; // Don't delete the assign, or V3Gate will freak out
|
||||
} else {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return true;
|
||||
}
|
||||
} else if (m_doV && VN_IS(nodep->lhsp(), Concat) && nodep->isTreePureRecurse()) {
|
||||
} else if (m_doV && VN_IS(nodep->lhsp(), Concat) && nodep->isPure()) {
|
||||
bool need_temp = false;
|
||||
if (m_warn && !VN_IS(nodep, AssignDly)) { // Is same var on LHS and RHS?
|
||||
// Note only do this (need user4) when m_warn, which is
|
||||
@@ -2085,7 +2076,7 @@ private:
|
||||
AstNodeExpr* const lc2p = VN_AS(nodep->lhsp(), Concat)->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const conp = VN_AS(nodep->lhsp(), Concat)->unlinkFrBack();
|
||||
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const rhs2p = rhsp->cloneTree(false);
|
||||
AstNodeExpr* const rhs2p = rhsp->cloneTreePure(false);
|
||||
// Calc widths
|
||||
const int lsb2 = 0;
|
||||
const int msb2 = lsb2 + lc2p->width() - 1;
|
||||
@@ -2140,8 +2131,8 @@ private:
|
||||
if (debug() >= 9 && newp) newp->dumpTreeAndNext(cout, "- _new: ");
|
||||
nodep->addNextHere(newp);
|
||||
// Cleanup
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(conp->deleteTree(), conp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(conp), conp);
|
||||
// Further reduce, either node may have more reductions.
|
||||
return true;
|
||||
} else if (m_doV && VN_IS(nodep->rhsp(), StreamR)) {
|
||||
@@ -2159,7 +2150,7 @@ private:
|
||||
srcp = new AstCvtDynArrayToPacked{srcp->fileline(), srcp, srcDTypep};
|
||||
}
|
||||
nodep->rhsp(srcp);
|
||||
VL_DO_DANGLING(streamp->deleteTree(), streamp);
|
||||
VL_DO_DANGLING(pushDeletep(streamp), streamp);
|
||||
// Further reduce, any of the nodes may have more reductions.
|
||||
return true;
|
||||
} else if (m_doV && VN_IS(nodep->lhsp(), StreamL)) {
|
||||
@@ -2201,7 +2192,7 @@ private:
|
||||
}
|
||||
nodep->lhsp(dstp);
|
||||
nodep->rhsp(srcp);
|
||||
VL_DO_DANGLING(streamp->deleteTree(), streamp);
|
||||
VL_DO_DANGLING(pushDeletep(streamp), streamp);
|
||||
// Further reduce, any of the nodes may have more reductions.
|
||||
return true;
|
||||
} else if (m_doV && VN_IS(nodep->rhsp(), StreamL)) {
|
||||
@@ -2251,7 +2242,7 @@ private:
|
||||
// widthMin no longer applicable if different C-expanded width
|
||||
newp->dtypeSetLogicSized(nodep->width(), VSigning::UNSIGNED);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
if (debug() >= 9) newp->dumpTree("- _new: ");
|
||||
}
|
||||
|
||||
@@ -2277,7 +2268,7 @@ private:
|
||||
newp->fileline(nodep->fileline());
|
||||
UINFO(4, "Simulate->" << newp << endl);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2309,7 +2300,7 @@ private:
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->stmtsp()) {
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
void visit(AstScope* nodep) override {
|
||||
@@ -2333,6 +2324,46 @@ private:
|
||||
iterate(nodep); // Again?
|
||||
}
|
||||
|
||||
bool containsMemberAccessRecurse(const AstNode* const nodep) {
|
||||
if (!nodep) return false;
|
||||
const auto it = m_containsMemberAccess.lower_bound(nodep);
|
||||
if (it != m_containsMemberAccess.end() && it->first == nodep) return it->second;
|
||||
bool result = false;
|
||||
if (VN_IS(nodep, MemberSel) || VN_IS(nodep, MethodCall) || VN_IS(nodep, CMethodCall)) {
|
||||
result = true;
|
||||
} else if (const AstNodeFTaskRef* const funcRefp = VN_CAST(nodep, NodeFTaskRef)) {
|
||||
if (containsMemberAccessRecurse(funcRefp->taskp())) result = true;
|
||||
} else if (const AstNodeCCall* const funcRefp = VN_CAST(nodep, NodeCCall)) {
|
||||
if (containsMemberAccessRecurse(funcRefp->funcp())) result = true;
|
||||
} else if (const AstNodeFTask* const funcp = VN_CAST(nodep, NodeFTask)) {
|
||||
// Assume that it has a member access
|
||||
if (funcp->recursive()) result = true;
|
||||
} else if (const AstCFunc* const funcp = VN_CAST(nodep, CFunc)) {
|
||||
if (funcp->recursive()) result = true;
|
||||
}
|
||||
if (!result) {
|
||||
result = containsMemberAccessRecurse(nodep->op1p())
|
||||
|| containsMemberAccessRecurse(nodep->op2p())
|
||||
|| containsMemberAccessRecurse(nodep->op3p())
|
||||
|| containsMemberAccessRecurse(nodep->op4p());
|
||||
}
|
||||
if (!result && !VN_IS(nodep, NodeFTask)
|
||||
&& !VN_IS(nodep, CFunc) // don't enter into next function
|
||||
&& containsMemberAccessRecurse(nodep->nextp())) {
|
||||
result = true;
|
||||
}
|
||||
m_containsMemberAccess.insert(it, std::make_pair(nodep, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool matchBiopToBitwise(AstNodeBiop* const nodep) {
|
||||
if (!m_convertLogicToBit) return false;
|
||||
if (!nodep->lhsp()->width1()) return false;
|
||||
if (!nodep->rhsp()->width1()) return false;
|
||||
if (!nodep->isPure()) return false;
|
||||
if (containsMemberAccessRecurse(nodep)) return false;
|
||||
return true;
|
||||
}
|
||||
bool matchConcatRand(AstConcat* nodep) {
|
||||
// CONCAT(RAND, RAND) - created by Chisel code
|
||||
AstRand* const aRandp = VN_CAST(nodep->lhsp(), Rand);
|
||||
@@ -2342,7 +2373,7 @@ private:
|
||||
UINFO(4, "Concat(Rand,Rand) => Rand: " << nodep << endl);
|
||||
aRandp->dtypeFrom(nodep); // I.e. the total width
|
||||
nodep->replaceWith(aRandp->unlinkFrBack());
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
}
|
||||
bool matchSelRand(AstSel* nodep) {
|
||||
@@ -2353,7 +2384,7 @@ private:
|
||||
UINFO(4, "Sel(Rand) => Rand: " << nodep << endl);
|
||||
aRandp->dtypeFrom(nodep); // I.e. the total width
|
||||
nodep->replaceWith(aRandp->unlinkFrBack());
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
}
|
||||
int operandConcatMove(AstConcat* nodep) {
|
||||
@@ -2393,7 +2424,7 @@ private:
|
||||
// If bp was a concat, then we have this exact same form again!
|
||||
// Recurse rather then calling node->iterate to prevent 2^n recursion!
|
||||
if (operandConcatMove(abConcp)) moveConcat(abConcp);
|
||||
VL_DO_DANGLING(bcConcp->deleteTree(), bcConcp);
|
||||
VL_DO_DANGLING(pushDeletep(bcConcp), bcConcp);
|
||||
} else {
|
||||
AstConcat* const abConcp = VN_AS(nodep->lhsp(), Concat);
|
||||
abConcp->unlinkFrBack();
|
||||
@@ -2404,7 +2435,7 @@ private:
|
||||
nodep->lhsp(ap);
|
||||
nodep->rhsp(bcConcp);
|
||||
if (operandConcatMove(bcConcp)) moveConcat(bcConcp);
|
||||
VL_DO_DANGLING(abConcp->deleteTree(), abConcp);
|
||||
VL_DO_DANGLING(pushDeletep(abConcp), abConcp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2430,11 +2461,11 @@ private:
|
||||
nodep->fileline(),
|
||||
new AstLogOr{nodep->fileline(), new AstLogNot{nodep->fileline(), lhsp}, rhsp},
|
||||
new AstLogOr{nodep->fileline(),
|
||||
new AstLogNot{nodep->fileline(), rhsp->cloneTree(false)},
|
||||
lhsp->cloneTree(false)}};
|
||||
new AstLogNot{nodep->fileline(), rhsp->cloneTreePure(false)},
|
||||
lhsp->cloneTreePure(false)}};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
void replaceSelSel(AstSel* nodep) {
|
||||
@@ -2450,8 +2481,8 @@ private:
|
||||
if (VN_IS(lsb1p, Const) && VN_IS(lsb2p, Const)) {
|
||||
newlsbp = new AstConst{lsb1p->fileline(),
|
||||
VN_AS(lsb1p, Const)->toUInt() + VN_AS(lsb2p, Const)->toUInt()};
|
||||
VL_DO_DANGLING(lsb1p->deleteTree(), lsb1p);
|
||||
VL_DO_DANGLING(lsb2p->deleteTree(), lsb2p);
|
||||
VL_DO_DANGLING(pushDeletep(lsb1p), lsb1p);
|
||||
VL_DO_DANGLING(pushDeletep(lsb2p), lsb2p);
|
||||
} else {
|
||||
// Width is important, we need the width of the fromp's expression, not the
|
||||
// potentially smaller lsb1p's width, but don't insert a redundant AstExtend.
|
||||
@@ -2471,7 +2502,7 @@ private:
|
||||
}
|
||||
AstSel* const newp = new AstSel{nodep->fileline(), fromp, newlsbp, widthp};
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
void replaceSelConcat(AstSel* nodep) {
|
||||
@@ -2502,7 +2533,7 @@ private:
|
||||
conRhsp->width() - nodep->lsbConst()}};
|
||||
nodep->replaceWith(newp);
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
bool operandSelReplicate(AstSel* nodep) {
|
||||
// SEL(REPLICATE(from,rep),lsb,width) => SEL(from,0,width) as long
|
||||
@@ -2526,7 +2557,7 @@ private:
|
||||
new AstConst{lsbp->fileline(), lsbp->toUInt() % fromp->width()}, widthp};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
}
|
||||
bool operandRepRep(AstReplicate* nodep) {
|
||||
@@ -2545,7 +2576,7 @@ private:
|
||||
= new AstReplicate{nodep->fileline(), from2p, cnt1p->toUInt() * cnt2p->toUInt()};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
}
|
||||
bool operandConcatSame(AstConcat* nodep) {
|
||||
@@ -2575,7 +2606,7 @@ private:
|
||||
AstReplicate* const newp = new AstReplicate{nodep->fileline(), from1p, cnt1 + cnt2};
|
||||
newp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return true;
|
||||
}
|
||||
void replaceSelIntoBiop(AstSel* nodep) {
|
||||
@@ -2588,12 +2619,12 @@ private:
|
||||
AstNodeExpr* const bilhsp = fromp->lhsp()->unlinkFrBack();
|
||||
AstNodeExpr* const birhsp = fromp->rhsp()->unlinkFrBack();
|
||||
//
|
||||
fromp->lhsp(
|
||||
new AstSel{nodep->fileline(), bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true)});
|
||||
fromp->lhsp(new AstSel{nodep->fileline(), bilhsp, lsbp->cloneTreePure(true),
|
||||
widthp->cloneTreePure(true)});
|
||||
fromp->rhsp(new AstSel{nodep->fileline(), birhsp, lsbp, widthp});
|
||||
fromp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(fromp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
void replaceSelIntoUniop(AstSel* nodep) {
|
||||
// SEL(NOT(a),1,bit) => NOT(SEL(a,bit))
|
||||
@@ -2607,7 +2638,7 @@ private:
|
||||
fromp->lhsp(new AstSel{nodep->fileline(), bilhsp, lsbp, widthp});
|
||||
fromp->dtypeFrom(nodep);
|
||||
nodep->replaceWith(fromp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
void visit(AstAttrOf* nodep) override {
|
||||
@@ -2639,7 +2670,7 @@ private:
|
||||
fromp->dtypeFrom(
|
||||
VN_AS(fromp->dtypep()->skipRefp(), NodeArrayDType)->subDTypep());
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
m_selp = nullptr;
|
||||
@@ -2687,12 +2718,12 @@ private:
|
||||
// support arrays of arrays or other stuff
|
||||
AstNode* const newp = valuep->cloneTree(false);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
did = true;
|
||||
} else if (nodep->varp()->isParam() && VN_IS(valuep, Unbounded)) {
|
||||
AstNode* const newp = valuep->cloneTree(false);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
did = true;
|
||||
}
|
||||
}
|
||||
@@ -2702,6 +2733,15 @@ private:
|
||||
<< nodep->varp()->prettyNameQ());
|
||||
}
|
||||
}
|
||||
void visit(AstExprStmt* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!AstNode::afterCommentp(nodep->stmtsp())) {
|
||||
UINFO(8, "ExprStmt(...) " << nodep << " " << nodep->resultp() << endl);
|
||||
nodep->replaceWith(nodep->resultp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
// Removing the ExprStmt might have made something impure above now pure
|
||||
}
|
||||
}
|
||||
void visit(AstEnumItemRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
UASSERT_OBJ(nodep->itemp(), nodep, "Not linked");
|
||||
@@ -2751,13 +2791,13 @@ private:
|
||||
} else {
|
||||
nodep->replaceWith(new AstSenItem{nodep->fileline(), AstSenItem::Never{}});
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
}
|
||||
} else { // Otherwise it may compute a result that needs to settle out
|
||||
nodep->replaceWith(new AstSenItem{nodep->fileline(), AstSenItem::Combo{}});
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
} else if (m_doNConst && VN_IS(nodep->sensp(), Not)) {
|
||||
// V3Gate may propagate NOTs into clocks... Just deal with it
|
||||
@@ -2771,7 +2811,7 @@ private:
|
||||
UINFO(8, "senItem(NOT...) " << nodep << " " << invert << endl);
|
||||
if (invert) nodep->edgeType(nodep->edgeType().invert());
|
||||
sensp->replaceWith(lastSensp->unlinkFrBack());
|
||||
VL_DO_DANGLING(sensp->deleteTree(), sensp);
|
||||
VL_DO_DANGLING(pushDeletep(sensp), sensp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2910,7 +2950,7 @@ private:
|
||||
|
||||
// Remove identical expressions
|
||||
if (lItemp->edgeType() == rItemp->edgeType()) {
|
||||
VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp);
|
||||
VL_DO_DANGLING(pushDeletep(rItemp->unlinkFrBack()), rItemp);
|
||||
nextp = lItemp;
|
||||
}
|
||||
|
||||
@@ -2927,7 +2967,7 @@ private:
|
||||
const V3Number lNum{lConstp->num()};
|
||||
lConstp->num().opOr(lNum, rConstp->num());
|
||||
// Remove redundant term
|
||||
VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp);
|
||||
VL_DO_DANGLING(pushDeletep(rItemp->unlinkFrBack()), rItemp);
|
||||
nextp = lItemp;
|
||||
}
|
||||
}
|
||||
@@ -2972,7 +3012,7 @@ private:
|
||||
AstInitial* const newinitp = new AstInitial{
|
||||
nodep->fileline(), new AstAssign{nodep->fileline(), varrefp, exprp}};
|
||||
m_modp->addStmtsp(newinitp);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
// Set the initial value right in the variable so we can constant propagate
|
||||
AstNode* const initvaluep = exprp->cloneTree(false);
|
||||
varrefp->varp()->valuep(initvaluep);
|
||||
@@ -2985,7 +3025,7 @@ private:
|
||||
AstRelease* const newRp = new AstRelease{flp, concatp->rhsp()->unlinkFrBack()};
|
||||
nodep->replaceWith(newLp);
|
||||
newLp->addNextHere(newRp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
visit(newLp);
|
||||
visit(newRp);
|
||||
}
|
||||
@@ -3012,23 +3052,24 @@ private:
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (!afterComment(nodep->thensp()) && !afterComment(nodep->elsesp())) {
|
||||
if (!nodep->condp()->isTreePureRecurse()) {
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (!AstNode::afterCommentp(nodep->thensp())
|
||||
&& !AstNode::afterCommentp(nodep->elsesp())) {
|
||||
if (!nodep->condp()->isPure()) {
|
||||
// Condition has side effect - leave - perhaps in
|
||||
// future simplify to remove all but side effect terms
|
||||
} else {
|
||||
// Empty block, remove it
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
}
|
||||
} else if (!afterComment(nodep->thensp())) {
|
||||
} else if (!AstNode::afterCommentp(nodep->thensp())) {
|
||||
UINFO(4, "IF({x}) nullptr {...} => IF(NOT{x}}: " << nodep << endl);
|
||||
AstNodeExpr* const condp = nodep->condp();
|
||||
AstNode* const elsesp = nodep->elsesp();
|
||||
condp->unlinkFrBackWithNext();
|
||||
elsesp->unlinkFrBackWithNext();
|
||||
if (nodep->thensp()) { // Must have been comment
|
||||
nodep->thensp()->unlinkFrBackWithNext()->deleteTree();
|
||||
pushDeletep(nodep->thensp()->unlinkFrBackWithNext());
|
||||
}
|
||||
nodep->condp(new AstLogNot{condp->fileline(),
|
||||
condp}); // LogNot, as C++ optimization also possible
|
||||
@@ -3045,7 +3086,7 @@ private:
|
||||
ifp->isBoundsCheck(nodep->isBoundsCheck()); // Copy bounds check info
|
||||
ifp->branchPred(nodep->branchPred().invert());
|
||||
nodep->replaceWith(ifp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (ifSameAssign(nodep)) {
|
||||
UINFO(
|
||||
4,
|
||||
@@ -3058,7 +3099,7 @@ private:
|
||||
AstNodeExpr* const falsep = elsesp->rhsp()->unlinkFrBack();
|
||||
thensp->rhsp(new AstCond{truep->fileline(), condp, truep, falsep});
|
||||
nodep->replaceWith(thensp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (false // Disabled, as vpm assertions are faster
|
||||
// without due to short-circuiting
|
||||
&& operandIfIf(nodep)) {
|
||||
@@ -3069,7 +3110,7 @@ private:
|
||||
AstNodeExpr* const lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext();
|
||||
nodep->condp(new AstLogAnd{lowerIfp->fileline(), condp, lowerCondp});
|
||||
lowerIfp->replaceWith(lowerThensp);
|
||||
VL_DO_DANGLING(lowerIfp->deleteTree(), lowerIfp);
|
||||
VL_DO_DANGLING(pushDeletep(lowerIfp), lowerIfp);
|
||||
} else if (operandBoolShift(nodep->condp())) {
|
||||
replaceBoolShift(nodep->condp());
|
||||
}
|
||||
@@ -3108,6 +3149,8 @@ private:
|
||||
// right line numbers, nor scopeNames as might be different scopes (late in process)
|
||||
if (!m_doCpp && pformatp->exprsp()) return false;
|
||||
if (!m_doCpp && nformatp->exprsp()) return false;
|
||||
if (pformatp->exprsp() && !pformatp->exprsp()->isPureAndNext()) return false;
|
||||
if (nformatp->exprsp() && !nformatp->exprsp()->isPureAndNext()) return false;
|
||||
// Avoid huge merges
|
||||
static constexpr int DISPLAY_MAX_MERGE_LENGTH = 500;
|
||||
if (pformatp->text().length() + nformatp->text().length() > DISPLAY_MAX_MERGE_LENGTH)
|
||||
@@ -3129,7 +3172,7 @@ private:
|
||||
scopeNamep->unlinkFrBackWithNext();
|
||||
pformatp->scopeNamep(scopeNamep);
|
||||
}
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return true;
|
||||
}
|
||||
void visit(AstSFormatF* nodep) override {
|
||||
@@ -3177,7 +3220,7 @@ private:
|
||||
<< argp << endl);
|
||||
// fmt = out w/ replace % with %% as it must be literal.
|
||||
fmt = VString::quotePercent(out);
|
||||
VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp);
|
||||
VL_DO_DANGLING(pushDeletep(argp->unlinkFrBack()), argp);
|
||||
}
|
||||
argp = nextp;
|
||||
}
|
||||
@@ -3237,7 +3280,7 @@ private:
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (nodep->condp()->isNeqZero()) {
|
||||
if (!thisWhileHasJumpDelay) {
|
||||
nodep->v3warn(INFINITELOOP, "Infinite loop (condition always true)");
|
||||
@@ -3260,13 +3303,13 @@ private:
|
||||
// Ignored, can eliminate early
|
||||
void visit(AstSysIgnore* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
if (m_doNConst) VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
}
|
||||
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->exprp() || VN_IS(nodep->exprp(), Const)) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
// TODO if there's an ExprStmt underneath just keep lower statements
|
||||
@@ -3286,14 +3329,14 @@ private:
|
||||
iterateChildren(nodep);
|
||||
// Jump to label where label immediately follows this go is not useful
|
||||
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
// Keep the label, might be other jumps pointing to it, gets cleaned later
|
||||
return;
|
||||
}
|
||||
if (m_doExpensive) {
|
||||
// Any non-label statements (at this statement level) can never execute
|
||||
while (nodep->nextp() && !VN_IS(nodep->nextp(), JumpLabel)) {
|
||||
nodep->nextp()->unlinkFrBack()->deleteTree();
|
||||
pushDeletep(nodep->nextp()->unlinkFrBack());
|
||||
}
|
||||
// If last statement in a jump label we have JumpLabel(...., JumpGo)
|
||||
// Often caused by "return" in a Verilog function. The Go is pointless, remove.
|
||||
@@ -3302,7 +3345,7 @@ private:
|
||||
if (aboveBlockp == nodep->labelp()->blockp()) {
|
||||
if (aboveBlockp->endStmtsp() == nodep->labelp()) {
|
||||
UINFO(4, "JUMPGO => last remove " << nodep << endl);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -3328,8 +3371,8 @@ private:
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
nodep->labelp()->unlinkFrBack()->deleteTree();
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
pushDeletep(nodep->labelp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3374,7 +3417,7 @@ private:
|
||||
TREEOPA("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)");
|
||||
// Zero on one side or the other
|
||||
TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstAnd {$lhsp.isZero, $rhsp, isTPure($rhsp)}", "replaceZero(nodep)"); // Can't use replaceZeroChkPure as we make this pattern in ChkPure
|
||||
TREEOP ("AstAnd {$lhsp.isZero, $rhsp, $rhsp.isPure}", "replaceZero(nodep)"); // Can't use replaceZeroChkPure as we make this pattern in ChkPure
|
||||
// This visit function here must allow for short-circuiting.
|
||||
TREEOPS("AstLogAnd {$lhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
@@ -3394,9 +3437,12 @@ private:
|
||||
TREEOP ("AstPowUS {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstPowSU {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstShiftL{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftR{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftL {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftLOvr {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftR {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftROvr {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftRS {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstShiftRSOvr{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
|
||||
TREEOP ("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstSub {$lhsp.isZero, $rhsp}", "AstNegate{$rhsp}");
|
||||
TREEOP ("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
@@ -3406,20 +3452,23 @@ private:
|
||||
TREEOP ("AstMul {$lhsp, $rhsp.isZero}", "replaceZeroChkPure(nodep,$lhsp)");
|
||||
TREEOP ("AstMulS {$lhsp, $rhsp.isZero}", "replaceZeroChkPure(nodep,$lhsp)");
|
||||
TREEOP ("AstOr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftL{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftR{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftRS{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftL {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftLOvr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftR {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftROvr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftRS {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftRSOvr{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstSub {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstXor {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
// Non-zero on one side or the other
|
||||
TREEOP ("AstAnd {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp.isNeqZero, $rhsp}", "replaceWRhsBool(nodep)");
|
||||
TREEOP ("AstOr {$lhsp.isAllOnes, $rhsp, isTPure($rhsp)}", "replaceWLhs(nodep)"); // ->allOnes
|
||||
TREEOP ("AstOr {$lhsp.isAllOnes, $rhsp, $rhsp.isPure}", "replaceWLhs(nodep)"); // ->allOnes
|
||||
TREEOP ("AstLogOr {$lhsp.isNeqZero, $rhsp}", "replaceNum(nodep,1)");
|
||||
TREEOP ("AstAnd {$lhsp, $rhsp.isAllOnes}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp, $rhsp.isNeqZero}", "replaceWLhsBool(nodep)");
|
||||
TREEOP ("AstOr {$lhsp, $rhsp.isAllOnes, isTPure($lhsp)}", "replaceWRhs(nodep)"); // ->allOnes
|
||||
TREEOP ("AstLogOr {$lhsp, $rhsp.isNeqZero, isTPure($lhsp), nodep->isPure()}", "replaceNum(nodep,1)");
|
||||
TREEOP ("AstOr {$lhsp, $rhsp.isAllOnes, $lhsp.isPure}", "replaceWRhs(nodep)"); // ->allOnes
|
||||
TREEOP ("AstLogOr {$lhsp, $rhsp.isNeqZero, $lhsp.isPure, nodep->isPure()}", "replaceNum(nodep,1)");
|
||||
TREEOP ("AstXor {$lhsp.isAllOnes, $rhsp}", "AstNot{$rhsp}");
|
||||
TREEOP ("AstMul {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
|
||||
@@ -3503,8 +3552,10 @@ private:
|
||||
TREEOPV("AstNot {$lhsp.castGteS, $lhsp.width1}", "AstLtS {$lhsp->castGteS()->lhsp(),$lhsp->castGteS()->rhsp()}");
|
||||
TREEOP ("AstLogNot{$lhsp.castGteS}", "AstLtS {$lhsp->castGteS()->lhsp(),$lhsp->castGteS()->rhsp()}");
|
||||
// Not common, but avoids compiler warnings about over shifting
|
||||
TREEOP ("AstShiftL{operandHugeShiftL(nodep)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstShiftR{operandHugeShiftR(nodep)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstShiftL {operandHugeShiftL(nodep)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstShiftLOvr{operandHugeShiftL(nodep)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstShiftR {operandHugeShiftR(nodep)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstShiftROvr{operandHugeShiftR(nodep)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstShiftL{operandShiftOp(nodep)}", "replaceShiftOp(nodep)");
|
||||
TREEOP ("AstShiftR{operandShiftOp(nodep)}", "replaceShiftOp(nodep)");
|
||||
TREEOP ("AstShiftL{operandShiftShift(nodep)}", "replaceShiftShift(nodep)");
|
||||
@@ -3591,9 +3642,9 @@ private:
|
||||
TREEOPV("AstOneHot{$lhsp.width1}", "replaceWLhs(nodep)");
|
||||
TREEOPV("AstOneHot0{$lhsp.width1}", "replaceNum(nodep,1)");
|
||||
// Binary AND/OR is faster than logical and/or (usually)
|
||||
TREEOPV("AstLogAnd{$lhsp.width1, $rhsp.width1, isTPure($lhsp), isTPure($rhsp)}", "AstAnd{$lhsp,$rhsp}");
|
||||
TREEOPV("AstLogOr {$lhsp.width1, $rhsp.width1, nodep->isPure(), isTPure($lhsp), isTPure($rhsp)}", "AstOr{$lhsp,$rhsp}");
|
||||
TREEOPV("AstLogNot{$lhsp.width1, isTPure($lhsp)}", "AstNot{$lhsp}");
|
||||
TREEOPV("AstLogAnd{matchBiopToBitwise(nodep)}", "AstAnd{$lhsp,$rhsp}");
|
||||
TREEOPV("AstLogOr {matchBiopToBitwise(nodep)}", "AstOr{$lhsp,$rhsp}");
|
||||
TREEOPV("AstLogNot{$lhsp.width1}", "AstNot{$lhsp}");
|
||||
// CONCAT(CONCAT({a},{b}),{c}) -> CONCAT({a},CONCAT({b},{c}))
|
||||
// CONCAT({const},CONCAT({const},{c})) -> CONCAT((constifiedCONC{const|const},{c}))
|
||||
TREEOPV("AstConcat{matchConcatRand(nodep)}", "DONE");
|
||||
@@ -3711,7 +3762,7 @@ public:
|
||||
case PROC_GENERATE: m_doV = true; m_doNConst = true; m_params = true;
|
||||
m_required = true; m_doGenerate = true; break;
|
||||
case PROC_LIVE: break;
|
||||
case PROC_V_WARN: m_doV = true; m_doNConst = true; m_warn = true; break;
|
||||
case PROC_V_WARN: m_doV = true; m_doNConst = true; m_warn = true; m_convertLogicToBit = true; break;
|
||||
case PROC_V_NOWARN: m_doV = true; m_doNConst = true; break;
|
||||
case PROC_V_EXPENSIVE: m_doV = true; m_doNConst = true; m_doExpensive = true; break;
|
||||
case PROC_CPP: m_doV = false; m_doNConst = true; m_doCpp = true; break;
|
||||
@@ -3730,6 +3781,7 @@ public:
|
||||
}
|
||||
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
VIsCached::clearCacheTree(); // Avoid using any stale isPure
|
||||
// Operate starting at a random place
|
||||
return iterateSubtreeReturnEdits(nodep);
|
||||
}
|
||||
|
||||
+15
-14
@@ -21,43 +21,44 @@
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Const final {
|
||||
public:
|
||||
static AstNode* constifyParamsEdit(AstNode* nodep);
|
||||
static AstNodeExpr* constifyParamsEdit(AstNodeExpr* exprp) {
|
||||
static AstNode* constifyParamsEdit(AstNode* nodep) VL_MT_DISABLED;
|
||||
static AstNodeExpr* constifyParamsEdit(AstNodeExpr* exprp) VL_MT_DISABLED {
|
||||
return VN_AS(constifyParamsEdit(static_cast<AstNode*>(exprp)), NodeExpr);
|
||||
}
|
||||
static AstNode* constifyParamsNoWarnEdit(AstNode* nodep);
|
||||
static AstNodeExpr* constifyParamsNoWarnEdit(AstNodeExpr* exprp) {
|
||||
static AstNode* constifyParamsNoWarnEdit(AstNode* nodep) VL_MT_DISABLED;
|
||||
static AstNodeExpr* constifyParamsNoWarnEdit(AstNodeExpr* exprp) VL_MT_DISABLED {
|
||||
return VN_AS(constifyParamsNoWarnEdit(static_cast<AstNode*>(exprp)), NodeExpr);
|
||||
}
|
||||
static AstNode* constifyGenerateParamsEdit(AstNode* nodep);
|
||||
static AstNode* constifyGenerateParamsEdit(AstNode* nodep) VL_MT_DISABLED;
|
||||
// Only do constant pushing, without removing dead logic
|
||||
static void constifyAllLive(AstNetlist* nodep);
|
||||
static void constifyAllLive(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
// Everything that's possible
|
||||
static void constifyAll(AstNetlist* nodep);
|
||||
static void constifyAll(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
// Also, warn
|
||||
static void constifyAllLint(AstNetlist* nodep);
|
||||
static void constifyAllLint(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
// C++ datatypes
|
||||
static void constifyCpp(AstNetlist* nodep);
|
||||
static void constifyCpp(AstNetlist* nodep) VL_MT_DISABLED;
|
||||
// Only the current node and lower
|
||||
// Return new node that may have replaced nodep
|
||||
static AstNode* constifyEditCpp(AstNode* nodep);
|
||||
static AstNodeExpr* constifyEditCpp(AstNodeExpr* exprp) {
|
||||
static AstNode* constifyEditCpp(AstNode* nodep) VL_MT_DISABLED;
|
||||
static AstNodeExpr* constifyEditCpp(AstNodeExpr* exprp) VL_MT_DISABLED {
|
||||
return VN_AS(constifyEditCpp(static_cast<AstNode*>(exprp)), NodeExpr);
|
||||
}
|
||||
// Only the current node and lower
|
||||
// Return new node that may have replaced nodep
|
||||
static AstNode* constifyEdit(AstNode* nodep);
|
||||
static AstNodeExpr* constifyEdit(AstNodeExpr* exprp) {
|
||||
static AstNode* constifyEdit(AstNode* nodep) VL_MT_DISABLED;
|
||||
static AstNodeExpr* constifyEdit(AstNodeExpr* exprp) VL_MT_DISABLED {
|
||||
return VN_AS(constifyEdit(static_cast<AstNode*>(exprp)), NodeExpr);
|
||||
}
|
||||
// Only the current node and lower, with special SenTree optimization
|
||||
// Return new node that may have replaced nodep
|
||||
static AstNode* constifyExpensiveEdit(AstNode* nodep);
|
||||
static AstNode* constifyExpensiveEdit(AstNode* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+4
-14
@@ -24,15 +24,10 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Coverage.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
@@ -82,7 +77,8 @@ private:
|
||||
CheckState m_state; // State save-restored on each new coverage scope/block
|
||||
AstNodeModule* m_modp = nullptr; // Current module to add statement to
|
||||
bool m_inToggleOff = false; // In function/task etc
|
||||
std::unordered_map<std::string, int> m_varnames; // Uniquification of inserted variable names
|
||||
// Uniquification of inserted variable names
|
||||
std::unordered_map<std::string, uint32_t> m_varnames;
|
||||
string m_beginHier; // AstBegin hier name for user coverage points
|
||||
std::unordered_map<int, LinenoSet>
|
||||
m_handleLines; // All line numbers for a given m_stateHandle
|
||||
@@ -146,13 +142,7 @@ private:
|
||||
string traceNameForLine(AstNode* nodep, const string& type) {
|
||||
string name = "vlCoverageLineTrace_" + nodep->fileline()->filebasenameNoExt() + "__"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + "_" + type;
|
||||
const auto it = m_varnames.find(name);
|
||||
if (it == m_varnames.end()) {
|
||||
m_varnames.emplace(name, 1);
|
||||
} else {
|
||||
const int suffix = (it->second)++;
|
||||
name += "_" + cvtToStr(suffix);
|
||||
}
|
||||
if (const uint32_t suffix = m_varnames[name]++) name += "_" + cvtToStr(suffix);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -20,6 +20,8 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
@@ -27,7 +29,7 @@ class AstNetlist;
|
||||
class V3Coverage final {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
static void coverage(AstNetlist* rootp);
|
||||
static void coverage(AstNetlist* rootp) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
@@ -17,13 +17,11 @@
|
||||
// If two COVERTOGGLEs have same VARSCOPE, combine them
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3CoverageJoin.h"
|
||||
|
||||
#include "V3DupFinder.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3ThreadSafety.h"
|
||||
|
||||
class AstNetlist;
|
||||
|
||||
//============================================================================
|
||||
@@ -27,7 +29,7 @@ class AstNetlist;
|
||||
class V3CoverageJoin final {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
static void coverageJoin(AstNetlist* rootp);
|
||||
static void coverageJoin(AstNetlist* rootp) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+2
-6
@@ -33,15 +33,10 @@
|
||||
// here after scoping to allow more dead node removal.
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Dead.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Global.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
@@ -531,6 +526,7 @@ public:
|
||||
|
||||
// We may have removed some datatypes, cleanup
|
||||
nodep->typeTablep()->repairCache();
|
||||
VIsCached::clearCacheTree(); // Removing assignments may affect isPure
|
||||
}
|
||||
~DeadVisitor() override = default;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user