2024-09-08 19:00:03 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
# DESCRIPTION: Verilator: Primitive C++ style checker
|
|
|
|
|
#
|
|
|
|
|
# Copyright 2024 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
|
|
|
|
|
|
|
|
|
|
import vltest_bootstrap
|
|
|
|
|
|
|
|
|
|
test.scenarios('dist')
|
|
|
|
|
|
|
|
|
|
Waivers = [
|
|
|
|
|
'+verilator+prof+threads+file+', # Deprecated
|
|
|
|
|
'+verilator+prof+threads+start+', # Deprecated
|
|
|
|
|
'+verilator+prof+threads+window+', # Deprecated
|
Deprecate clocker attribute and --clk option (#6463)
The only use for the clocker attribute and the AstVar::isUsedClock that
is actually necessary today for correctness is to mark top level inputs
of --lib-create blocks as being (or driving) a clock signal. Correctness
of --lib-create (and hence hierarchical blocks) actually used to depend
on having the right optimizations eliminate intermediate clocks (e.g.:
V3Gate), when the top level port was not used directly in a sensitivity
list, or marking top level signals manually via --clk or the clocker
attribute. However V3Sched::partition already needs to trace through the
logic to figure out what signals might drive a sensitivity list, so it
can very easily mark all top level inputs as such.
In this patch we remove the AstVar::attrClocker and AstVar::isUsedClock
attributes, and replace them with AstVar::isPrimaryClock, automatically
set by V3Sched::partition. This eliminates all need for manual
annotation so we are deprecating the --clk/--no-clk options and the
clocker/no_clocker attributes.
This also eliminates the opportunity for any further mis-optimization
similar to #6453.
Regarding the other uses of the removed AstVar attributes:
- As of 5.000, initial edges are triggered via a separate mechanism
applied in V3Sched, so the use in V3EmitCFunc.cpp is redundant
- Also as of 5.000, we can handle arbitrary sensitivity expressions, so
the restriction on eliminating clock signals in V3Gate is unnecessary
- Since the recent change when Dfg is applied after V3Scope, it does
perform the equivalent of GateClkDecomp, so we can delete that pass.
2025-09-20 16:50:22 +02:00
|
|
|
'-clk', # Deprecated
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
'-fdfg-synthesize-all', # Mostly used for testing
|
2024-09-08 19:00:03 +02:00
|
|
|
'-fno-', # Documented differently
|
Deprecate clocker attribute and --clk option (#6463)
The only use for the clocker attribute and the AstVar::isUsedClock that
is actually necessary today for correctness is to mark top level inputs
of --lib-create blocks as being (or driving) a clock signal. Correctness
of --lib-create (and hence hierarchical blocks) actually used to depend
on having the right optimizations eliminate intermediate clocks (e.g.:
V3Gate), when the top level port was not used directly in a sensitivity
list, or marking top level signals manually via --clk or the clocker
attribute. However V3Sched::partition already needs to trace through the
logic to figure out what signals might drive a sensitivity list, so it
can very easily mark all top level inputs as such.
In this patch we remove the AstVar::attrClocker and AstVar::isUsedClock
attributes, and replace them with AstVar::isPrimaryClock, automatically
set by V3Sched::partition. This eliminates all need for manual
annotation so we are deprecating the --clk/--no-clk options and the
clocker/no_clocker attributes.
This also eliminates the opportunity for any further mis-optimization
similar to #6453.
Regarding the other uses of the removed AstVar attributes:
- As of 5.000, initial edges are triggered via a separate mechanism
applied in V3Sched, so the use in V3EmitCFunc.cpp is redundant
- Also as of 5.000, we can handle arbitrary sensitivity expressions, so
the restriction on eliminating clock signals in V3Gate is unnecessary
- Since the recent change when Dfg is applied after V3Scope, it does
perform the equivalent of GateClkDecomp, so we can delete that pass.
2025-09-20 16:50:22 +02:00
|
|
|
'-no-clk', # Deprecated
|
2024-09-08 19:00:03 +02:00
|
|
|
'-no-lineno', # Deprecated
|
|
|
|
|
'-no-order-clock-delay', # Deprecated
|
2025-05-22 12:45:39 +02:00
|
|
|
'-prof-threads', # Deprecated
|
2024-09-08 19:00:03 +02:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
2025-09-14 14:43:52 +02:00
|
|
|
def get_summary_opts():
|
2024-09-08 19:00:03 +02:00
|
|
|
args = {}
|
2025-09-14 14:43:52 +02:00
|
|
|
for filename in test.glob_some(test.root + "/bin/*"):
|
2024-09-08 19:00:03 +02:00
|
|
|
with open(filename, "r", encoding="latin-1") as fh:
|
|
|
|
|
on = False
|
|
|
|
|
lineno = 0
|
|
|
|
|
for line in fh:
|
|
|
|
|
lineno += 1
|
|
|
|
|
line = line.rstrip()
|
|
|
|
|
m1 = re.search(r'^\s+((-|\+)+[^ ]+)', line)
|
|
|
|
|
m2 = re.search(r"parser.add_argument\('((-|\+)[^']+)'", line)
|
|
|
|
|
if re.search(r'ARGUMENT SUMMARY', line):
|
|
|
|
|
on = True
|
|
|
|
|
elif re.search(r'=head1', line):
|
|
|
|
|
on = False
|
|
|
|
|
elif on and m1:
|
|
|
|
|
opt = opt_clean(m1.group(1))
|
|
|
|
|
if test.verbose:
|
|
|
|
|
print("S '" + opt + "' " + line)
|
|
|
|
|
args[opt] = filename + ":" + str(lineno)
|
|
|
|
|
elif m2:
|
|
|
|
|
opt = opt_clean(m2.group(1))
|
|
|
|
|
if test.verbose:
|
|
|
|
|
print("S '" + opt + "' " + line)
|
|
|
|
|
args[opt] = filename + ":" + str(lineno)
|
|
|
|
|
return args
|
|
|
|
|
|
|
|
|
|
|
2025-09-14 14:43:52 +02:00
|
|
|
def get_docs_opts():
|
2024-09-08 19:00:03 +02:00
|
|
|
args = {}
|
2025-09-14 14:43:52 +02:00
|
|
|
for filename in test.glob_some(test.root + "/docs/guide/*.rst"):
|
2024-09-08 19:00:03 +02:00
|
|
|
with open(filename, "r", encoding="latin-1") as fh:
|
|
|
|
|
lineno = 0
|
|
|
|
|
for line in fh:
|
|
|
|
|
lineno += 1
|
|
|
|
|
line = line.rstrip()
|
|
|
|
|
m = re.search(r'option:: ((-|\+)+[^ `]+)', line)
|
|
|
|
|
if not m:
|
|
|
|
|
m = re.search(r':vlopt:`[^`]+ <([^>]+)>', line)
|
|
|
|
|
if not m:
|
|
|
|
|
m = re.search(r':vlopt:`((-|\+)+[^ `]+)', line)
|
|
|
|
|
if m:
|
|
|
|
|
opt = opt_clean(m.group(1))
|
|
|
|
|
if test.verbose:
|
|
|
|
|
print("D '" + opt + "' " + line)
|
|
|
|
|
args[opt] = filename + ":" + str(lineno)
|
|
|
|
|
return args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def opt_clean(opt):
|
|
|
|
|
opt = re.sub(r'--', '-', opt)
|
|
|
|
|
opt = re.sub(r'<.*', '', opt)
|
|
|
|
|
opt = re.sub(r'\\', '', opt)
|
|
|
|
|
return opt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def alt_names(opt):
|
|
|
|
|
opts = [opt]
|
|
|
|
|
if re.search(r'^-', opt):
|
|
|
|
|
opts.append("-no" + opt)
|
|
|
|
|
m = re.search(r'^-no(-.*)', opt)
|
|
|
|
|
if m:
|
|
|
|
|
opts.append(m.group(1))
|
|
|
|
|
return opts
|
|
|
|
|
|
|
|
|
|
|
2025-09-14 14:43:52 +02:00
|
|
|
if not os.path.exists(test.root + "/.git"):
|
2024-09-08 19:00:03 +02:00
|
|
|
test.skip("Not in a git repository")
|
|
|
|
|
|
2025-09-14 14:43:52 +02:00
|
|
|
sums = get_summary_opts()
|
|
|
|
|
docs = get_docs_opts()
|
2024-09-08 19:00:03 +02:00
|
|
|
|
|
|
|
|
both = {}
|
|
|
|
|
both.update(sums)
|
|
|
|
|
both.update(docs)
|
|
|
|
|
|
|
|
|
|
waiver = {k: 1 for k in Waivers}
|
|
|
|
|
|
|
|
|
|
for opt in sorted(both.keys()):
|
|
|
|
|
if opt in waiver:
|
|
|
|
|
continue
|
|
|
|
|
sum_ok = False
|
|
|
|
|
docs_ok = False
|
|
|
|
|
for alt in alt_names(opt):
|
|
|
|
|
if alt in sums:
|
|
|
|
|
sum_ok = True
|
|
|
|
|
if test.verbose:
|
|
|
|
|
print(str(sum_ok) + " SAC '" + opt + "' -> '" + alt + "'")
|
|
|
|
|
if re.search(r'-fno-', opt): # Minimal-documented optimization option
|
|
|
|
|
sum_ok = True
|
|
|
|
|
for alt in alt_names(opt):
|
|
|
|
|
if alt in docs:
|
|
|
|
|
docs_ok = True
|
|
|
|
|
if test.verbose:
|
|
|
|
|
print(str(docs_ok) + " DAC '" + opt + "' -> '" + alt + "'")
|
|
|
|
|
|
|
|
|
|
if not sum_ok:
|
|
|
|
|
test.error(docs[opt] + ": Option documented in docs/guide '" + opt +
|
|
|
|
|
"' not found in bin/* ARGUMENT SUMMARY documentation")
|
|
|
|
|
elif not docs_ok:
|
|
|
|
|
test.error(sums[opt] + ": Option documented in bin/ ARGUMENT SUMMARY '" + opt +
|
|
|
|
|
"' not found in docs/guide documentation")
|
|
|
|
|
elif test.verbose:
|
|
|
|
|
print(": ok '" + opt)
|
|
|
|
|
|
|
|
|
|
test.passes()
|