mirror of
https://github.com/verilator/verilator.git
synced 2024-12-29 10:47:34 +00:00
Commentary
This commit is contained in:
parent
e02f97854c
commit
33105f017c
@ -73,7 +73,7 @@ for you.
|
||||
Performance
|
||||
===========
|
||||
|
||||
Verilator does not simply convert Verilog HDL to C++ or SystemC. Rather,
|
||||
Verilator does not directly translate Verilog HDL to C++ or SystemC. Rather,
|
||||
Verilator compiles your code into a much faster optimized and optionally
|
||||
thread-partitioned model, which is in turn wrapped inside a C++/SystemC
|
||||
module. The results are a compiled Verilog model that executes even on a
|
||||
|
@ -200,7 +200,7 @@ DPI System Task/Functions
|
||||
-------------------------
|
||||
|
||||
Verilator extends the DPI format to allow using the same scheme to
|
||||
efficiently add system functions. Simply use a dollar-sign prefixed system
|
||||
efficiently add system functions. Use a dollar-sign prefixed system
|
||||
function name for the import, but note it must be escaped.
|
||||
|
||||
.. code-block:: sv
|
||||
@ -508,7 +508,7 @@ structure. If a ``VerilatedContext`` is not created prior to creating a
|
||||
model, a default global one is created automatically.
|
||||
|
||||
The ``Verilated::`` methods, including the ``Verilated::commandArgs`` call
|
||||
shown above, simply call VerilatedContext methods using the default global
|
||||
shown above, call VerilatedContext methods using the default global
|
||||
VerilatedContext. (Technically they operate on the last one used by a
|
||||
given thread.) If you are using multiple simulation contexts you should
|
||||
not use the Verilated:: methods, and instead always use VerilatedContext
|
||||
|
@ -99,10 +99,10 @@ Summary:
|
||||
.. option:: --bbox-sys
|
||||
|
||||
Black box any unknown $system task or function calls. System tasks will
|
||||
simply become no-operations, and system functions will be replaced with
|
||||
unsized zero. Arguments to such functions will be parsed, but not
|
||||
otherwise checked. This prevents errors when linting in the presence of
|
||||
company specific PLI calls.
|
||||
become no-operations, and system functions will be replaced with unsized
|
||||
zero. Arguments to such functions will be parsed, but not otherwise
|
||||
checked. This prevents errors when linting in the presence of company
|
||||
specific PLI calls.
|
||||
|
||||
Using this argument will likely cause incorrect simulation.
|
||||
|
||||
|
@ -354,8 +354,8 @@ also use the "import DPI" SystemVerilog feature to call C code (see the
|
||||
chapter above). There is also limited VPI access to public signals.
|
||||
|
||||
If you want something more complex, since Verilator emits standard C++
|
||||
code, you can simply write your own C++ routines that can access and modify
|
||||
signal values without needing any PLI interface code, and call it with
|
||||
code, you can write your own C++ routines that can access and modify signal
|
||||
values without needing any PLI interface code, and call it with
|
||||
$c("{any_c++_statement}").
|
||||
|
||||
See the :ref:`Connecting` section.
|
||||
@ -482,7 +482,7 @@ by your code or you'll get strange results.
|
||||
Should a module be in Verilog or SystemC?
|
||||
"""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Sometimes there is a block that just interconnects instances, and have a
|
||||
Sometimes there is a block that only interconnects instances, and have a
|
||||
choice as to if you write it in Verilog or SystemC. Everything else being
|
||||
equal, best performance is when Verilator sees all of the design. So, look
|
||||
at the hierarchy of your design, labeling instances as to if they are
|
||||
|
@ -92,7 +92,7 @@ appropriate code to detect failing cases at simulation runtime and print an
|
||||
|
||||
Verilator likewise also asserts any "unique" or "priority" SystemVerilog
|
||||
keywords on case statement, as well as "unique" on if statements. However,
|
||||
"priority if" is currently simply ignored.
|
||||
"priority if" is currently ignored.
|
||||
|
||||
|
||||
.. _Language Limitations:
|
||||
@ -174,9 +174,9 @@ Structures and Unions
|
||||
---------------------
|
||||
|
||||
Presently Verilator only supports packed structs and packed unions. Rand
|
||||
and randc tags on members are simply 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
|
||||
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.
|
||||
|
||||
|
||||
|
@ -433,8 +433,8 @@ directly without any prefix.
|
||||
If results from multiple simulations are to be used in generating the
|
||||
optimization, multiple simulation's profile.vlt may be concatenated
|
||||
externally, or each of the files may be fed as separate command line
|
||||
options into Verilator. Verilator will simply sum the profile results, so
|
||||
a longer running test will have proportionally more weight for optimization
|
||||
options into Verilator. Verilator will sum the profile results, so a
|
||||
longer running test will have proportionally more weight for optimization
|
||||
than a shorter running test.
|
||||
|
||||
If you provide any profile feedback data to Verilator, and it cannot use
|
||||
|
@ -12,7 +12,7 @@ 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. Simply surround the offending line with a
|
||||
will include a warning code. Surround the offending line with a
|
||||
:code:`/*verilator&32;lint_off*/` and :code:`/*verilator&32;lint_on*/`
|
||||
metacomment pair:
|
||||
|
||||
@ -162,7 +162,7 @@ List Of Warnings
|
||||
always @(posedge clk) foo[0] <= ...
|
||||
always_comb foo[1] = ...
|
||||
|
||||
Simply use a different register for the flop:
|
||||
Instead use a different register for the flop:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
@ -284,7 +284,7 @@ List Of Warnings
|
||||
|
||||
.. TODO better example
|
||||
|
||||
Warns that it is simply better style to use casez, and "?" in place of
|
||||
Warns that it is better style to use casez, and "?" in place of
|
||||
"x"'s. See
|
||||
`http://www.sunburst-design.com/papers/CummingsSNUG1999Boston_FullParallelCase_rev1_1.pdf
|
||||
<http://www.sunburst-design.com/papers/CummingsSNUG1999Boston_FullParallelCase_rev1_1.pdf>`_
|
||||
@ -1212,10 +1212,10 @@ List Of Warnings
|
||||
.. include:: ../../docs/gen/ex_STMTDLY_msg.rst
|
||||
|
||||
This is a warning because Verilator does not support delayed statements.
|
||||
It will simply ignore all such delays. In many cases ignoring a delay
|
||||
might be harmless, but if the delayed statement is, as in this example,
|
||||
used to cause some important action at a later time, it might be an
|
||||
important difference.
|
||||
It will ignore all such delays. In many cases ignoring a delay might be
|
||||
harmless, but if the delayed statement is, as in this example, used to
|
||||
cause some important action at a later time, it might be an important
|
||||
difference.
|
||||
|
||||
Some possible workarounds:
|
||||
|
||||
|
@ -268,11 +268,11 @@ Estimating Logic Costs
|
||||
|
||||
To compute the cost of any given path through the graph, Verilator
|
||||
estimates an execution cost for each task. Each macro-task has an execution
|
||||
cost which is simply the sum of its tasks' costs. We assume that
|
||||
communication overhead and synchronization overhead are zero, so the cost
|
||||
of any given path through the graph is simply the sum of macro-task
|
||||
execution costs. Sarkar does almost the same thing, except that he has
|
||||
nonzero estimates for synchronization costs.
|
||||
cost which is the sum of its tasks' costs. We assume that communication
|
||||
overhead and synchronization overhead are zero, so the cost of any given
|
||||
path through the graph is the sum of macro-task execution costs. Sarkar
|
||||
does almost the same thing, except that he has nonzero estimates for
|
||||
synchronization costs.
|
||||
|
||||
Verilator's cost estimates are assigned by ``InstrCountCostVisitor``. This
|
||||
class is perhaps the most fragile piece of the multithread
|
||||
@ -817,7 +817,7 @@ which you can install using cpan.
|
||||
|
||||
There are some traps to avoid when running regression tests
|
||||
|
||||
- When checking the MANIFEST, the test will barf on unexpected code in the
|
||||
- When checking the MANIFEST, the test will fail on unexpected code in the
|
||||
Verilator tree. So make sure to keep any such code outside the tree.
|
||||
|
||||
- Not all Linux systems install Perldoc by default. This is needed for the
|
||||
@ -1186,7 +1186,7 @@ anticipated to be ever implemented for the reasons indicated.
|
||||
IEEE 1800-2017 3.3 modules within modules
|
||||
Little/no tool support, and arguably not a good practice.
|
||||
IEEE 1800-2017 6.12 "shortreal"
|
||||
Little/no tool support, and easily simply promoted to real.
|
||||
Little/no tool support, and easily promoted to real.
|
||||
IEEE 1800-2017 11.11 Min, typ, max
|
||||
No SDF support so will always use typical.
|
||||
IEEE 1800-2017 11.12 "let"
|
||||
|
@ -69,7 +69,7 @@ int main(int argc, char** argv, char** env) {
|
||||
// Historical note, before Verilator 4.200 Verilated::gotFinish()
|
||||
// was used above in place of contextp->gotFinish().
|
||||
// Most of the contextp-> calls can use Verilated:: calls instead;
|
||||
// the Verilated:: versions simply assume there's a single context
|
||||
// the Verilated:: versions just assume there's a single context
|
||||
// being used (per thread). It's faster and clearer to use the
|
||||
// newer contextp-> versions.
|
||||
|
||||
|
@ -1678,7 +1678,7 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
|
||||
VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
|
||||
break;
|
||||
}
|
||||
default: // Other simulators simply return 0 in these cases and don't error out
|
||||
default: // Other simulators return 0 in these cases and don't error out
|
||||
return 0;
|
||||
}
|
||||
_vl_clean_inplace_w(rbits, rwp);
|
||||
|
@ -417,7 +417,7 @@ static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value, int narg
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// DPI accessors that simply call above functions
|
||||
// DPI accessors that call above functions
|
||||
|
||||
void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) {
|
||||
const VerilatedDpiOpenVar* const varp = _vl_openhandle_varp(h);
|
||||
|
@ -489,7 +489,7 @@ public:
|
||||
public: // But only for verilated.cpp
|
||||
// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
// Slow ok - called once/scope on destruction, so we only iterate.
|
||||
const VerilatedLockGuard lock{s().m_userMapMutex};
|
||||
for (auto it = s().m_userMap.begin(); it != s().m_userMap.end();) {
|
||||
if (it->first.first == scopep) {
|
||||
|
@ -610,7 +610,7 @@ def getGcovCoverage(args):
|
||||
coverage_files = getFilteredCoverageFiles(coverage_files, args.excludepre)
|
||||
logging.info("Found {} coverage files after filtering".format(len(coverage_files)))
|
||||
|
||||
# We "zero" the "counters" by simply deleting all gcda files
|
||||
# We "zero" the "counters" by deleting all gcda files
|
||||
if args.zerocounters:
|
||||
removeFiles(coverage_files)
|
||||
logging.info("Removed {} .gcda files".format(len(coverage_files)))
|
||||
|
@ -262,7 +262,7 @@ private:
|
||||
if (itemp->isDefault()) has_default = true;
|
||||
}
|
||||
if (nodep->fullPragma() || nodep->priorityPragma()) {
|
||||
// Simply need to add a default if there isn't one already
|
||||
// Need to add a default if there isn't one already
|
||||
++m_statAsFull;
|
||||
if (!has_default) {
|
||||
nodep->addItemsp(new AstCaseItem(
|
||||
|
@ -2562,7 +2562,7 @@ private:
|
||||
string m_text;
|
||||
|
||||
protected:
|
||||
// Node that simply puts text into the output stream
|
||||
// Node that puts text into the output stream
|
||||
AstNodeText(VNType t, FileLine* fl, const string& textp)
|
||||
: AstNode{t, fl} {
|
||||
m_text = textp; // Copy it
|
||||
|
@ -4927,7 +4927,7 @@ private:
|
||||
bool m_generate; // Underneath a generate
|
||||
const bool m_implied; // Not inserted by user
|
||||
public:
|
||||
// Node that simply puts name into the output stream
|
||||
// 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)
|
||||
@ -4951,7 +4951,7 @@ class AstFork final : public AstNodeBlock {
|
||||
private:
|
||||
VJoinType m_joinType; // Join keyword type
|
||||
public:
|
||||
// Node that simply puts name into the output stream
|
||||
// Node that puts name into the output stream
|
||||
AstFork(FileLine* fl, const string& name, AstNode* stmtsp)
|
||||
: ASTGEN_SUPER_Fork(fl, name, stmtsp) {}
|
||||
ASTNODE_NODE_FUNCS(Fork)
|
||||
|
@ -117,7 +117,7 @@ public:
|
||||
};
|
||||
|
||||
// User pointer allocator classes. T_Node is the type of node the allocator should be applied to
|
||||
// and is simply there for a bit of extra type safety. T_Data is the type of the data structure
|
||||
// and is there for a bit of extra type safety. T_Data is the type of the data structure
|
||||
// managed by the allocator.
|
||||
template <class T_Node, class T_Data>
|
||||
class AstUser1Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 1> {};
|
||||
|
@ -384,7 +384,7 @@ private:
|
||||
VL_DANGLING(iconstp);
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
} else {
|
||||
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
|
||||
// Not a caseX mask, we can build CASEEQ(cexpr icond)
|
||||
AstNode* const and1p = cexprp->cloneTree(false);
|
||||
AstNode* const and2p = icondp;
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
|
@ -2658,7 +2658,7 @@ private:
|
||||
// SENTREE(... SENITEM(x), SENGATE(SENITEM(x),*) ...) => SENITEM(x)
|
||||
// Do we need the SENITEM's to be identical? No because we're
|
||||
// ORing between them; we just need to ensure that the result is at
|
||||
// least as frequently activating. So we simply
|
||||
// least as frequently activating. So we
|
||||
// SENGATE(SENITEM(x)) -> SENITEM(x), then let it collapse with the
|
||||
// other SENITEM(x).
|
||||
{
|
||||
|
@ -176,7 +176,7 @@ private:
|
||||
// newfuncp->addStmtsp(new AstStop(newfuncp->fileline()));
|
||||
if (debug() >= 9) newfuncp->dumpTree(cout, " newfunc: ");
|
||||
} else {
|
||||
// Only a single function under this name, we can simply rename it
|
||||
// Only a single function under this name, we can rename it
|
||||
UINFO(6, " Wrapping " << name << " just one " << topFuncp << endl);
|
||||
topFuncp->name(name);
|
||||
}
|
||||
|
@ -1137,7 +1137,7 @@ public:
|
||||
} else if (nodep->isWide()) {
|
||||
UASSERT_OBJ(m_wideTempRefp, nodep, "Wide Constant w/ no temp");
|
||||
emitConstant(nodep, m_wideTempRefp, "");
|
||||
m_wideTempRefp = nullptr; // We used it, barf if set it a second time
|
||||
m_wideTempRefp = nullptr; // We used it, fail if set it a second time
|
||||
} else {
|
||||
emitConstant(nodep, nullptr, "");
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ public:
|
||||
}
|
||||
}
|
||||
void varUsageReplace(AstVarScope* nodep, AstVarRef* varrefp) {
|
||||
// Variable rvalue. If it references a constant, we can simply replace it
|
||||
// Variable rvalue. If it references a constant, we can replace it
|
||||
const auto it = m_map.find(nodep);
|
||||
if (it != m_map.end()) {
|
||||
if (AstConst* const constp = it->second.constNodep()) {
|
||||
|
@ -259,7 +259,7 @@ public:
|
||||
// table's import wouldn't warn
|
||||
} else if (VN_IS(nodep, Begin) && VN_IS(fnodep, Begin)
|
||||
&& VN_AS(nodep, Begin)->generate()) {
|
||||
// Begin: ... blocks often replicate under genif/genfor, so simply
|
||||
// Begin: ... blocks often replicate under genif/genfor, so
|
||||
// suppress duplicate checks. See t_gen_forif.v for an example.
|
||||
} else {
|
||||
UINFO(4, "name " << name << endl); // Not always same as nodep->name
|
||||
|
@ -344,7 +344,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Is it simply 'lhs = cond'?
|
||||
// Is it 'lhs = cond'?
|
||||
if (assignp->rhsp()->sameTree(m_mgCondp)) return true;
|
||||
}
|
||||
}
|
||||
|
@ -698,7 +698,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
|
||||
// To get the number of digits required, we want to compute
|
||||
// log10(2**mantissabits) and round it up. To be able to handle
|
||||
// a very wide mantissa, we use log2(2**mantissabits)/log2(10),
|
||||
// which is simply (+1.0 is for rounding bias):
|
||||
// which is (+1.0 is for rounding bias):
|
||||
double dchars = mantissabits / 3.321928094887362 + 1.0;
|
||||
if (issigned) dchars++; // space for sign
|
||||
fmtsize = cvtToStr(int(dchars));
|
||||
|
@ -138,7 +138,7 @@ private:
|
||||
}
|
||||
|
||||
// Copy blocks into this scope
|
||||
// If this is the first usage of the block ever, we can simply move the reference
|
||||
// If this is the first usage of the block ever, we can move the reference
|
||||
iterateChildren(nodep);
|
||||
|
||||
// ***Note m_scopep is passed back to the caller of the routine (above)
|
||||
|
@ -70,7 +70,7 @@ class SimulateVisitor VL_NOT_FINAL : public VNVisitor {
|
||||
// Test the tree to see if it is conformant
|
||||
// Given a set of input values, find the output values
|
||||
// Both are done in this same visitor to reduce risk; if a visitor
|
||||
// is missing, we will simply not apply the optimization, rather then bomb.
|
||||
// is missing, we will not apply the optimization, rather then bomb.
|
||||
|
||||
private:
|
||||
// NODE STATE
|
||||
|
@ -142,7 +142,7 @@ private:
|
||||
|
||||
struct EdgeListCmp final {
|
||||
bool operator()(const EdgeList* ap, const EdgeList* bp) const {
|
||||
// Simply compare heads
|
||||
// Compare heads
|
||||
return edgeCmp(bp->back(), ap->back());
|
||||
}
|
||||
};
|
||||
|
@ -1281,7 +1281,7 @@ private:
|
||||
varScopep->user5(true); // Mark as already added
|
||||
// Note: We are ignoring function locals as they should not be referenced
|
||||
// anywhere outside of the enclosing AstCFunc, and therefore they are
|
||||
// irrelevant for code ordering. This is simply an optimization to avoid adding
|
||||
// irrelevant for code ordering. This is an optimization to avoid adding
|
||||
// useless nodes to the ordering graph in V3Order.
|
||||
if (varScopep->varp()->isFuncLocal()) return;
|
||||
writtenps.push_back(varScopep);
|
||||
@ -1426,7 +1426,7 @@ private:
|
||||
"Ignoring return value of non-void function (IEEE 1800-2017 13.4.1)");
|
||||
}
|
||||
// outvscp maybe non-nullptr if calling a function in a taskref,
|
||||
// but if so we want to simply ignore the function result
|
||||
// but if so we want to ignore the function result
|
||||
nodep->replaceWith(beginp);
|
||||
}
|
||||
// Cleanup
|
||||
|
@ -188,7 +188,7 @@ private:
|
||||
v3Global.rootp()->typeTablep()->addTypesp(nodep);
|
||||
}
|
||||
void visitIterateNodeDType(AstNodeDType* nodep) {
|
||||
// Rather than use dtypeChg which may make new nodes, we simply edit in place,
|
||||
// Rather than use dtypeChg which may make new nodes, we edit in place,
|
||||
// as we don't need to preserve any widthMin's, and every dtype with the same width
|
||||
// gets an identical edit.
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
|
@ -1303,7 +1303,7 @@ port<nodep>: // ==IEEE: port
|
||||
// // data_declarationVarFront
|
||||
//
|
||||
// // Though not type for interfaces, we factor out the port direction and type
|
||||
// // so we can simply handle it in one place
|
||||
// // so we can handle it in one place
|
||||
//
|
||||
// // IEEE: interface_port_header port_identifier { unpacked_dimension }
|
||||
// // Expanded interface_port_header
|
||||
@ -5525,7 +5525,7 @@ pexpr<nodep>: // IEEE: property_expr (The name pexpr is important as regexps j
|
||||
//UNSUP // // IEEE: '(' sexpr {',' sequence_match_item } ')' [ sequence_abbrev ]
|
||||
//UNSUP // // As sequence_expr includes expression_or_dist, and boolean_abbrev includes sequence_abbrev:
|
||||
//UNSUP // // '(' sequence_expr {',' sequence_match_item } ')' [ boolean_abbrev ]
|
||||
//UNSUP // // "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can simply drop it
|
||||
//UNSUP // // "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can drop it
|
||||
//UNSUP | '(' ~p~sexpr ')' { $<fl>$ = $<fl>1; $$ = ...; }
|
||||
//UNSUP | '(' ~p~sexpr ',' sequence_match_itemList ')' { }
|
||||
//UNSUP //
|
||||
|
@ -201,7 +201,7 @@ int main() {
|
||||
logReg(dut->clk, "read c", c, " (after clk)");
|
||||
// "c" is continuously assigned as the inverse of "a", but in
|
||||
// Verilator, that means that it will only change value when "a"
|
||||
// changes on the posedge of a clock. Put simply, "c" always holds the
|
||||
// changes on the posedge of a clock. That is "c" always holds the
|
||||
// inverse of the "after clock" value of "a".
|
||||
checkResult(c == (1 - a), "Test of scalar wire reading failed.");
|
||||
}
|
||||
@ -231,7 +231,7 @@ int main() {
|
||||
|
||||
// "d" is continuously assigned as the (8-bit) bitwise inverse of "b",
|
||||
// but in Verilator, that means that it will only change value when
|
||||
// "b" changes on the posedge of a clock. Put simply, "d" always holds
|
||||
// "b" changes on the posedge of a clock. That is "d" always holds
|
||||
// the inverse of the "after clock" value of "b".
|
||||
checkResult(d == ((~b) & 0xff), "Test of vector wire reading failed.");
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ module testbench;
|
||||
endfunction;
|
||||
|
||||
// Downstream signal dependent on clk demonstrates scheduling issue.
|
||||
// The '$c("1") &' simply ensures that dependent_clk does not get
|
||||
// The '$c("1") &' ensures that dependent_clk does not get
|
||||
// replaced with clk early and hence hiding the issue
|
||||
wire dependent_clk = $c1("1") & clk;
|
||||
|
||||
|
@ -13,7 +13,7 @@ scenarios(vlt => 1);
|
||||
top_filename("$Self->{obj_dir}/$Self->{name}.v");
|
||||
golden_filename("$Self->{obj_dir}/$Self->{name}.out");
|
||||
|
||||
# Rather then having to maintain a new .v and .out, simply add returns
|
||||
# Rather then having to maintain a new .v and .out, add returns
|
||||
# to all lines of the existing t_preproc test.
|
||||
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user