mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 00:23:35 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58fc922737 | ||
|
|
3b5c791332 | ||
|
|
6e16bc1b7b | ||
|
|
1aba0f6379 | ||
|
|
11cfa3c072 | ||
|
|
59141b1678 | ||
|
|
2083c071ce | ||
|
|
3ad5872d30 | ||
|
|
ea6bb21cdc | ||
|
|
3d4fe0364a |
@@ -3,17 +3,25 @@ Revision history for Verilator
|
||||
The contributors that suggested a given feature are shown in []. [by ...]
|
||||
indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
* Verilator 3.62**
|
||||
* Verilator 3.622 10/17/2006 Stable
|
||||
|
||||
**** Fix link error when using --exe with --trace. [Eugene Weber]
|
||||
**** Fix --skip-identical without --debug, broken in 3.621. [Andy Meier]
|
||||
|
||||
**** Public functions now allow > 64 bit arguments.
|
||||
* Verilator 3.621 10/11/2006 Beta
|
||||
|
||||
**** Don't core dump on errors when not under --debug. [Allan Cochrane]
|
||||
** Add /*verilator no_inline_task*/ to prevent over-expansion. [Eugene Weber]
|
||||
|
||||
*** Public functions now allow > 64 bit arguments.
|
||||
|
||||
**** Remove .vpp intermediate files when not under --debug.
|
||||
|
||||
* Verilator 3.620 10/04/2006
|
||||
**** Fix link error when using --exe with --trace. [Eugene Weber]
|
||||
|
||||
**** Fix mis-optimization of wide concats with constants.
|
||||
|
||||
**** Fix core dump on printing error when not under --debug. [Allan Cochrane]
|
||||
|
||||
* Verilator 3.620 10/04/2006 Stable
|
||||
|
||||
*** Support simple inout task ports. [Eugene Weber]
|
||||
|
||||
@@ -436,7 +444,7 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
**** Added NC Verilog as alternative to VCS for reference tests.
|
||||
|
||||
**** Support implicit wire declarations on input-only signals.
|
||||
(Dangerous, as leads to wires without drivers, but allowed by spec.)
|
||||
(Dangerous, as leads to wires without drivers, but allowed by spec.)
|
||||
|
||||
**** Fixed compile warnings on Suse 9.1
|
||||
|
||||
|
||||
+68
-18
@@ -407,7 +407,7 @@ compatibility.
|
||||
|
||||
=item --psl
|
||||
|
||||
Enable PSL parsing. Without this switch, psl meta-comments are ignored.
|
||||
Enable PSL parsing. Without this switch, PSL meta-comments are ignored.
|
||||
See the --assert flag to enable all assertions, and --coverage-user to
|
||||
enable functional coverage.
|
||||
|
||||
@@ -609,7 +609,7 @@ Then we convert the SystemPerl output to SystemC.
|
||||
$SYSTEMPERL/sp_preproc --preproc *.sp
|
||||
|
||||
(You can also skip the above sp_preproc by getting pure SystemC from
|
||||
verilator by replacing the verilator --sp flag in the previous step with
|
||||
Verilator by replacing the verilator --sp flag in the previous step with
|
||||
-sc.)
|
||||
|
||||
We then can compile it
|
||||
@@ -938,7 +938,7 @@ call C++ functions from your Verilog code.
|
||||
String arguments will be put directly into the output C++ code. Expression
|
||||
arguments will have the code to evaluate the expression inserted. Thus to
|
||||
call a C++ function, $c("func(",a,")") will result in 'func(a)' in the
|
||||
output C++ code. For input arguments, rather then hardcoding variable
|
||||
output C++ code. For input arguments, rather then hard-coding variable
|
||||
names in the string $c("func(a)"), instead pass the variable as an
|
||||
expression $c("func(",a,")"). This will allow the call to work inside
|
||||
Verilog functions where the variable is flattened out, and also enable
|
||||
@@ -1056,6 +1056,14 @@ Disable the specified warning message for any warnings following the comment.
|
||||
|
||||
Re-enable the specified warning message for any warnings following the comment.
|
||||
|
||||
=item /*verilator no_inline_task*/
|
||||
|
||||
Used in a function or task variable definition section to specify the
|
||||
function or task should not be inlined into where it is used. This may
|
||||
reduce the size of the final executable when a task is used a very large
|
||||
number of times. For this flag to work, the task and tasks below it must
|
||||
be pure; they cannot reference any variables outside the task itself.
|
||||
|
||||
=item /*verilator sc_clock*/
|
||||
|
||||
Used after a input declaration to indicate the signal should be declared in
|
||||
@@ -1271,7 +1279,7 @@ appropriate width.
|
||||
$display and friends must have a constant format string as the first
|
||||
argument (as with C's printf), you cannot simply list variables standalone.
|
||||
|
||||
=head1 ERRORS
|
||||
=head1 ERRORS AND WARNINGS
|
||||
|
||||
Warnings may be disabled in two ways. First, when the warning is
|
||||
printed it will include a warning code. Simply surround the offending
|
||||
@@ -1281,13 +1289,13 @@ line with a warn_off/warn_on pair:
|
||||
if (`DEF_THAT_IS_EQ_ZERO <= 3) $stop;
|
||||
// verilator lint_on UNSIGNED
|
||||
|
||||
They may also be globally disabled by invoking Verilator with the
|
||||
C<-Wno-I<warning>> switch. 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 successfully compile your design.
|
||||
Warnings may also be globally disabled by invoking Verilator with the
|
||||
C<-Wno-I<warning>> switch. 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 successfully
|
||||
compile your design.
|
||||
|
||||
Warnings:
|
||||
List of all warnings:
|
||||
|
||||
=over 4
|
||||
|
||||
@@ -1344,12 +1352,41 @@ signal before it is implicitly declared by a cell, and can lead to dangling
|
||||
nets. A better option is the /*AUTOWIRE*/ feature of Verilog-Mode for
|
||||
Emacs, available from L<http://www.veripool.com/>
|
||||
|
||||
=item IMPURE
|
||||
|
||||
Warns that a task or function that has been marked with /*verilator
|
||||
no_inline_task*/ references variables that are not local to the task.
|
||||
Verilator cannot schedule these variables correctly.
|
||||
|
||||
=item MULTIDRIVEN
|
||||
|
||||
Warns that the specified signal comes from multiple always blocks. This is
|
||||
often unsupported by synthesis tools, and is considered bad style. It will
|
||||
also cause longer runtimes due to reduced optimizations.
|
||||
|
||||
=item TASKNSVAR
|
||||
|
||||
Error when a call to a task or function has a output from that task tied to
|
||||
a non-simple signal. Instead connect the task output to a temporary signal
|
||||
of the appropriate width, and use that signal to set the appropriate
|
||||
expression as the next statement. For example:
|
||||
|
||||
task foo; output sig; ... endtask
|
||||
always @* begin
|
||||
foo(bus_we_select_from[2]); // Will get TASKNSVAR error
|
||||
end
|
||||
|
||||
Change this to:
|
||||
|
||||
reg foo_temp_out;
|
||||
always @* begin
|
||||
foo(foo_temp_out);
|
||||
bus_we_select_from[2] = foo_temp_out;
|
||||
end
|
||||
|
||||
Verilator doesn't do this conversion for you, as some more complicated
|
||||
cases would result in simulator mismatches.
|
||||
|
||||
=item UNDRIVEN
|
||||
|
||||
Warns that the specified signal is never sourced.
|
||||
@@ -1375,11 +1412,11 @@ may be only one particular usage of a multiply instantiated block. The
|
||||
construct should be cleaned up to improve runtime; two times better
|
||||
performance may be possible by fixing these warnings.
|
||||
|
||||
Unlike UNOPT this occurs after netlist flattening, and indicates a more
|
||||
basic problem, as the less obvious case described under UNOPT does not
|
||||
apply.
|
||||
Unlike the UNOPT warning, this occurs after netlist flattening, and
|
||||
indicates a more basic problem, as the less obvious case described under
|
||||
UNOPT does not apply.
|
||||
|
||||
Often this is caused by logic that isn't truly circular as viewed by
|
||||
Often UNOPTFLAT is caused by logic that isn't truly circular as viewed by
|
||||
synthesis which analyzes interconnection per-bit, but is circular to
|
||||
simulation which analyzes per-bus:
|
||||
|
||||
@@ -1387,12 +1424,25 @@ simulation which analyzes per-bus:
|
||||
|
||||
This statement needs to be evaluated multiple times, as a change in
|
||||
"shift_in" requires "x" to be computed 3 times before it becomes stable.
|
||||
For significantly better performance, split this into 2 separate signals:
|
||||
For significantly better performance, split this into 2 separate signals,
|
||||
and then if necessary generate the original signal:
|
||||
|
||||
wire [2:1] x_21 = x[1:0];
|
||||
wire [0:0] x_0 = shift_in;
|
||||
wire [2:0] x = {x_21, x_0};
|
||||
|
||||
This warning may also be due to clock enables. To fix these, use the
|
||||
This logic needs to be evaluated only once. These sort of changes may also
|
||||
speed up your traditional event driven simulator, as it will result in
|
||||
fewer events per cycle.
|
||||
|
||||
The most complicated UNOPTFLAT path we've seen was due to low bits of a bus
|
||||
being generated from an always statement that consumed high bits of the
|
||||
same bus processed by another series of always blocks. The fix is the
|
||||
same; split it into two separate signals, then create the bus from the two
|
||||
separate signals.
|
||||
|
||||
The UNOPTFLAT warning may also be due to clock enables, identified from the
|
||||
reported path going through a clock gating cell. To fix these, use the
|
||||
clock_enable meta comment described above.
|
||||
|
||||
=item UNSIGNED
|
||||
@@ -1450,8 +1500,8 @@ that is not yet supported in Verilator. See the Limitations chapter.
|
||||
=item Verilated model didn't converge
|
||||
|
||||
Verilator sometimes has to evaluate combinatorial logic multiple times,
|
||||
usually around code where a UNOPT warning was issued, but disabled. For
|
||||
example:
|
||||
usually around code where a UNOPTFLAT warning was issued, but disabled.
|
||||
For example:
|
||||
|
||||
always @ (a) b=~a;
|
||||
always @ (b) a=b
|
||||
|
||||
@@ -1328,6 +1328,38 @@ static inline WDataOutP VL_CONST_W_16X(int obits, WDataOutP o,
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
|
||||
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
|
||||
_END(obits,16); }
|
||||
static inline WDataOutP VL_CONST_W_17X(int obits, WDataOutP o,
|
||||
I d16,
|
||||
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
|
||||
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
|
||||
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
|
||||
o[16]=d16;
|
||||
_END(obits,17); }
|
||||
static inline WDataOutP VL_CONST_W_18X(int obits, WDataOutP o,
|
||||
I d17,I d16,
|
||||
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
|
||||
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
|
||||
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
|
||||
o[16]=d16; o[17]=d17;
|
||||
_END(obits,18); }
|
||||
static inline WDataOutP VL_CONST_W_19X(int obits, WDataOutP o,
|
||||
I d18,I d17,I d16,
|
||||
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
|
||||
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
|
||||
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
|
||||
o[16]=d16; o[17]=d17; o[18]=d18;
|
||||
_END(obits,19); }
|
||||
static inline WDataOutP VL_CONST_W_20X(int obits, WDataOutP o,
|
||||
I d19,I d18,I d17,I d16,
|
||||
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
|
||||
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
|
||||
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
|
||||
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
|
||||
o[16]=d16; o[17]=d17; o[18]=d18; o[19]=d19;
|
||||
_END(obits,20); }
|
||||
static inline WDataOutP VL_CONST_W_24X(int obits, WDataOutP o,
|
||||
I d23,I d22,I d21,I d20,I d19,I d18,I d17,I d16,
|
||||
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
COVERAGE_BLOCK_OFF,
|
||||
INLINE_MODULE,
|
||||
NO_INLINE_MODULE,
|
||||
NO_INLINE_TASK,
|
||||
PUBLIC_MODULE,
|
||||
PUBLIC_TASK
|
||||
};
|
||||
|
||||
+3
-1
@@ -349,7 +349,8 @@ void AstVar::dump(ostream& str) {
|
||||
if (isSigPublic()) str<<" [P]";
|
||||
if (attrClockEn()) str<<" [aCLKEN]";
|
||||
if (attrFileDescr()) str<<" [aFD]";
|
||||
if (isFuncLocal() || isFuncReturn()) str<<" [FUNC]";
|
||||
if (isFuncReturn()) str<<" [FUNCRTN]";
|
||||
else if (isFuncLocal()) str<<" [FUNC]";
|
||||
str<<" "<<varType();
|
||||
}
|
||||
void AstSenTree::dump(ostream& str) {
|
||||
@@ -375,6 +376,7 @@ void AstNodeFTaskRef::dump(ostream& str) {
|
||||
}
|
||||
void AstNodeFTask::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (taskPublic()) str<<" [PUBLIC]";
|
||||
}
|
||||
void AstCoverDecl::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
|
||||
@@ -239,6 +239,10 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
insureCleanAndNext (nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstCCall* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureCleanAndNext (nodep->argsp());
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
|
||||
+14
-16
@@ -96,22 +96,20 @@ public:
|
||||
string cFuncArgs(AstCFunc* nodep) {
|
||||
// Return argument list for given C function
|
||||
string args = nodep->argTypes();
|
||||
if (args=="") {
|
||||
// Might be a user function with argument list.
|
||||
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
if (args != "") args+= ", ";
|
||||
if (portp->isWide()) {
|
||||
if (portp->isInOnly()) args += "const ";
|
||||
args += portp->cType();
|
||||
args += " (& "+portp->name();
|
||||
args += ")["+cvtToStr(portp->widthWords())+"]";
|
||||
} else {
|
||||
args += portp->cType();
|
||||
if (portp->isOutput()) args += "&";
|
||||
args += " "+portp->name();
|
||||
}
|
||||
// Might be a user function with argument list.
|
||||
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
if (args != "") args+= ", ";
|
||||
if (portp->isWide()) {
|
||||
if (portp->isInOnly()) args += "const ";
|
||||
args += portp->cType();
|
||||
args += " (& "+portp->name();
|
||||
args += ")["+cvtToStr(portp->widthWords())+"]";
|
||||
} else {
|
||||
args += portp->cType();
|
||||
if (portp->isOutput()) args += "&";
|
||||
args += " "+portp->name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ public:
|
||||
bool optSystemPerl() { return v3Global.opt.systemPerl(); }
|
||||
static string symClassName() { return v3Global.opt.prefix()+"__Syms"; }
|
||||
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
|
||||
static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp = vlSymsp->TOPp;"; }
|
||||
static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
|
||||
static string modClassName(AstModule* modp) { // Return name of current module being processed
|
||||
if (modp->isTop()) {
|
||||
return v3Global.opt.prefix();
|
||||
|
||||
+5
-5
@@ -92,7 +92,7 @@ void FileLine::lineDirective(const char* textp) {
|
||||
|
||||
bool FileLine::warnOff(const string& msg, bool flag) {
|
||||
V3ErrorCode code (msg.c_str());
|
||||
if (code == V3ErrorCode::ERROR) {
|
||||
if (code < V3ErrorCode::FIRST_WARN) {
|
||||
return false;
|
||||
} else {
|
||||
warnOff(code, flag);
|
||||
@@ -168,9 +168,8 @@ void FileLine::v3errorEnd(ostringstream& str) {
|
||||
void V3Error::init() {
|
||||
for (int i=0; i<V3ErrorCode::MAX; i++) {
|
||||
s_describedEachWarn[i] = false;
|
||||
s_pretendError[i] = false;
|
||||
s_pretendError[i] = V3ErrorCode(i).pretendError();
|
||||
}
|
||||
pretendError(V3ErrorCode::BLKANDNBLK, true);
|
||||
|
||||
if (string(V3ErrorCode(V3ErrorCode::MAX).ascii()) != " MAX") {
|
||||
v3fatalSrc("Enum table in V3ErrorCode::ascii() is munged");
|
||||
@@ -204,8 +203,9 @@ void V3Error::abortIfErrors() {
|
||||
string V3Error::msgPrefix(V3ErrorCode code) {
|
||||
if (code==V3ErrorCode::SUPPRESS) return "-arning-suppressed: ";
|
||||
else if (code==V3ErrorCode::FATAL) return "%Error: ";
|
||||
else if (code==V3ErrorCode::ERROR
|
||||
|| s_pretendError[code]) return "%Error: ";
|
||||
else if (code==V3ErrorCode::ERROR) return "%Error: ";
|
||||
else if (code<V3ErrorCode::FIRST_WARN
|
||||
|| s_pretendError[code]) return "%Error-"+(string)code.ascii()+": ";
|
||||
else return "%Warning-"+(string)code.ascii()+": ";
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -34,9 +34,12 @@ public:
|
||||
enum en {
|
||||
SUPPRESS, // Warning suppressed by user
|
||||
FATAL, // Kill the program
|
||||
ERROR, // Error out, can't suppress
|
||||
ERROR, // General error out, can't suppress
|
||||
// Error codes:
|
||||
TASKNSVAR, // Error: Task I/O not simple
|
||||
// Warning codes:
|
||||
FIRST_WARN, // Just a code so the program knows where to start warnings
|
||||
//
|
||||
BLKANDNBLK, // Blocked and non-blocking assignments to same variable
|
||||
CASEINCOMPLETE, // Case statement has missing values
|
||||
CASEOVERLAP, // Case statements overlap
|
||||
@@ -45,6 +48,7 @@ public:
|
||||
COMBDLY, // Combinatorial delayed assignment
|
||||
GENCLK, // Generated Clock
|
||||
IMPLICIT, // Implicit wire
|
||||
IMPURE, // Impure function not being inlined
|
||||
MULTIDRIVEN, // Driven from multiple blocks
|
||||
UNDRIVEN, // No drivers
|
||||
UNOPT, // Unoptimizable block
|
||||
@@ -66,10 +70,11 @@ public:
|
||||
const char* names[] = {
|
||||
// Leading spaces indicate it can't be disabled.
|
||||
" SUPPRESS", " FATAL", " ERROR",
|
||||
"TASKNSVAR",
|
||||
" FIRST_WARN",
|
||||
"BLKANDNBLK",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEX", "CMPCONST",
|
||||
"COMBDLY", "GENCLK", "IMPLICIT",
|
||||
"COMBDLY", "GENCLK", "IMPLICIT", "IMPURE",
|
||||
"MULTIDRIVEN",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
|
||||
"VARHIDDEN", "WIDTH",
|
||||
@@ -79,6 +84,9 @@ public:
|
||||
};
|
||||
// Warnings that warn about nasty side effects
|
||||
bool dangerous() const { return ( m_e==COMBDLY );};
|
||||
// Warnings we'll present to the user as errors
|
||||
// Later -Werror- options may make more of these.
|
||||
bool pretendError() const { return ( m_e==BLKANDNBLK || m_e==IMPURE); };
|
||||
};
|
||||
inline bool operator== (V3ErrorCode lhs, V3ErrorCode rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator== (V3ErrorCode lhs, V3ErrorCode::en rhs) { return (lhs.m_e == rhs); }
|
||||
|
||||
@@ -660,6 +660,9 @@ private:
|
||||
// Lhs or Rhs may be word, long, or quad.
|
||||
// newAstWordSelClone nicely abstracts the difference.
|
||||
int rhsshift = rhsp->rhsp()->widthMin();
|
||||
// Sometimes doing the words backwards is preferrable.
|
||||
// When we have x={x,foo} backwards is better, when x={foo,x} forward is better
|
||||
// However V3Subst tends to rip this up, so not worth optimizing now.
|
||||
for (int w=0; w<rhsp->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstOr (rhsp->fileline(),
|
||||
|
||||
@@ -42,6 +42,9 @@ public:
|
||||
}
|
||||
static ofstream* new_ofstream(const string& filename, bool append=false) {
|
||||
addTgtDepend(filename);
|
||||
return new_ofstream_nodepend (filename, append);
|
||||
}
|
||||
static ofstream* new_ofstream_nodepend(const string& filename, bool append=false) {
|
||||
if (append) {
|
||||
return new ofstream(filename.c_str(), ios::app);
|
||||
} else {
|
||||
|
||||
+3
-1
@@ -374,7 +374,9 @@ private:
|
||||
//UINFO(4," CCALL "<<nodep<<endl);
|
||||
nodep->iterateChildren(*this);
|
||||
// Enter the function and trace it
|
||||
nodep->funcp()->accept(*this);
|
||||
if (!nodep->funcp()->entryPoint()) { // else is non-inline or public function we optimize separately
|
||||
nodep->funcp()->accept(*this);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep, AstNUser*) {
|
||||
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
|
||||
|
||||
@@ -141,6 +141,7 @@ class V3Options {
|
||||
bool trace() const { return m_trace; }
|
||||
bool traceDups() const { return m_traceDups; }
|
||||
bool outFormatOk() const { return m_outFormatOk; }
|
||||
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
|
||||
bool pins64() const { return m_pins64; }
|
||||
bool profileCFuncs() const { return m_profileCFuncs; }
|
||||
bool psl() const { return m_psl; }
|
||||
|
||||
@@ -79,6 +79,8 @@ protected:
|
||||
ostream* osp;
|
||||
if (v3Global.opt.preprocOnly()) {
|
||||
osp = &cout;
|
||||
} else if (!v3Global.opt.keepTempFiles()) { // Must match unlink rule in V3Read.cpp
|
||||
osp = ofp = V3File::new_ofstream_nodepend(vppFilename);
|
||||
} else {
|
||||
osp = ofp = V3File::new_ofstream(vppFilename);
|
||||
}
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ void V3Read::readFile(FileLine* fileline, const string& modfilename, bool inLibr
|
||||
lexFile (vppfilename, modfilename);
|
||||
}
|
||||
|
||||
if (!V3Error::debugDefault()) {
|
||||
if (!v3Global.opt.keepTempFiles()) { // Must match new_ofstream_nodepend rule in V3PreShell.cpp
|
||||
unlink (vppfilename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
+153
-52
@@ -19,10 +19,11 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3Subst's Transformations:
|
||||
//
|
||||
//
|
||||
// Each module:
|
||||
// Search all ASSIGN(WORDSEL(...)) and build what it's assigned to
|
||||
// Later usages of that word may then be replaced
|
||||
// Later usages of that word may then be replaced as long as
|
||||
// the RHS hasn't changed value.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
@@ -44,76 +45,97 @@
|
||||
|
||||
class SubstBaseVisitor : public AstNVisitor {
|
||||
public:
|
||||
static int debug() { return 0; }
|
||||
static int debug() { return V3Error::debugDefault(); }
|
||||
// static int debug() { return 9; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Subst state, as a visitor of each AstNode
|
||||
// Class for each word of a multi-word variable
|
||||
|
||||
class SubstVarWord {
|
||||
protected:
|
||||
// MEMBERS
|
||||
AstNodeAssign* m_assignp; // Last assignment to each word of this var
|
||||
int m_step; // Step number of last assignment
|
||||
bool m_use; // True if each word was consumed
|
||||
bool m_complex; // True if each word is complex
|
||||
friend class SubstVarEntry;
|
||||
// METHODS
|
||||
void clear() {
|
||||
m_assignp = NULL;
|
||||
m_step = 0;
|
||||
m_use = false;
|
||||
m_complex = false;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Class for every variable we may process
|
||||
|
||||
class SubstVarEntry {
|
||||
// MEMBERS
|
||||
AstVar* m_varp; // Variable this tracks
|
||||
bool m_complexAssign;// True if assigned multiple times or in complex mannor
|
||||
AstNodeAssign* m_wholeAssignp; // Last assignment to entire array
|
||||
bool m_wholeUse; // True if used as entire wide array
|
||||
bool m_wordAssign; // True if any word assignments
|
||||
bool m_wordUse; // True if any individual word usage
|
||||
vector<AstNodeAssign*> m_wordAssignps; // Last assignment to each word of this var
|
||||
vector<bool> m_wordUses; // True if each word was consumed
|
||||
vector<bool> m_wordComplex; // True if each word is complex
|
||||
SubstVarWord m_whole; // Data for whole vector used at once
|
||||
vector<SubstVarWord> m_words; // Data for every word, if multi word variable
|
||||
int debug() { return SubstBaseVisitor::debug(); }
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
SubstVarEntry (AstVar* varp) { // Construction for when a var is used
|
||||
m_varp = varp;
|
||||
m_complexAssign = false;
|
||||
m_wholeAssignp = NULL;
|
||||
m_wholeUse = false;
|
||||
m_whole.m_use = false;
|
||||
m_wordAssign = false;
|
||||
m_wordUse = false;
|
||||
m_wordAssignps.resize(varp->widthWords());
|
||||
m_wordUses.resize(varp->widthWords());
|
||||
m_wordComplex.resize(varp->widthWords());
|
||||
m_words.resize(varp->widthWords());
|
||||
m_whole.clear();
|
||||
for (int i=0; i<varp->widthWords(); i++) {
|
||||
m_wordAssignps[i] = NULL;
|
||||
m_wordUses[i] = false;
|
||||
m_wordComplex[i] = false;
|
||||
m_words[i].clear();
|
||||
}
|
||||
}
|
||||
bool wordNumOk(int word) {
|
||||
~SubstVarEntry() {}
|
||||
private:
|
||||
// METHODS
|
||||
bool wordNumOk(int word) const {
|
||||
return word < m_varp->widthWords();
|
||||
}
|
||||
AstNodeAssign* getWordAssignp(int word) {
|
||||
AstNodeAssign* getWordAssignp(int word) const {
|
||||
if (!wordNumOk(word)) return NULL;
|
||||
else return m_wordAssignps[word];
|
||||
else return m_words[word].m_assignp;
|
||||
}
|
||||
void assignWhole (AstNodeAssign* assp) {
|
||||
if (m_wholeAssignp) m_complexAssign = true;
|
||||
m_wholeAssignp = assp;
|
||||
public:
|
||||
void assignWhole (int step, AstNodeAssign* assp) {
|
||||
if (m_whole.m_assignp) m_whole.m_complex = true;
|
||||
m_whole.m_assignp = assp;
|
||||
m_whole.m_step = step;
|
||||
}
|
||||
void assignWord (int word, AstNodeAssign* assp) {
|
||||
if (!wordNumOk(word) || getWordAssignp(word) || m_wordComplex[word]) m_complexAssign = true;
|
||||
void assignWord (int step, int word, AstNodeAssign* assp) {
|
||||
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) m_whole.m_complex = true;
|
||||
m_wordAssign = true;
|
||||
if (wordNumOk(word)) m_wordAssignps[word] = assp;
|
||||
if (wordNumOk(word)) {
|
||||
m_words[word].m_assignp = assp;
|
||||
m_words[word].m_step = step;
|
||||
}
|
||||
}
|
||||
void assignWordComplex (int word) {
|
||||
if (!wordNumOk(word) || getWordAssignp(word) || m_wordComplex[word]) m_complexAssign = true;
|
||||
m_wordComplex[word] = true;
|
||||
void assignWordComplex (int step, int word) {
|
||||
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) m_whole.m_complex = true;
|
||||
m_words[word].m_complex = true;
|
||||
}
|
||||
void assignComplex() {
|
||||
m_complexAssign = true;
|
||||
void assignComplex(int step) {
|
||||
m_whole.m_complex = true;
|
||||
}
|
||||
void consumeWhole() { //==consumeComplex as we don't know the difference
|
||||
m_wholeUse = true;
|
||||
m_whole.m_use = true;
|
||||
}
|
||||
void consumeWord(int word) {
|
||||
m_wordUses[word] = true;
|
||||
m_words[word].m_use = true;
|
||||
m_wordUse = true;
|
||||
}
|
||||
// ACCESSORS
|
||||
AstNode* substWhole(AstNode* errp) {
|
||||
if (!m_varp->isWide()
|
||||
&& !m_complexAssign && m_wholeAssignp && !m_wordAssign) {
|
||||
AstNodeAssign* assp = m_wholeAssignp;
|
||||
&& !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
|
||||
AstNodeAssign* assp = m_whole.m_assignp;
|
||||
if (!assp) errp->v3fatalSrc("Reading whole that was never assigned");
|
||||
return (assp->rhsp());
|
||||
} else {
|
||||
@@ -121,7 +143,7 @@ public:
|
||||
}
|
||||
}
|
||||
AstNode* substWord(AstNode* errp, int word) { // Return what to substitute given word number for
|
||||
if (!m_complexAssign && !m_wholeAssignp && !m_wordComplex[word]) {
|
||||
if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) {
|
||||
AstNodeAssign* assp = getWordAssignp(word);
|
||||
if (!assp) errp->v3fatalSrc("Reading a word that was never assigned, or bad word #");
|
||||
return (assp->rhsp());
|
||||
@@ -129,34 +151,90 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
int getWholeStep() const {
|
||||
return m_whole.m_step;
|
||||
}
|
||||
int getWordStep(int word) const {
|
||||
if (!wordNumOk(word)) return 0; else return m_words[word].m_step;
|
||||
}
|
||||
void deleteAssign (AstNodeAssign* nodep) {
|
||||
UINFO(5, "Delete "<<nodep<<endl);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
void deleteUnusedAssign() {
|
||||
// If there are unused assignments in this var, kill them
|
||||
if (!m_wholeUse && !m_wordUse && m_wholeAssignp) {
|
||||
deleteAssign (m_wholeAssignp); m_wholeAssignp=NULL;
|
||||
if (!m_whole.m_use && !m_wordUse && m_whole.m_assignp) {
|
||||
deleteAssign (m_whole.m_assignp); m_whole.m_assignp=NULL;
|
||||
}
|
||||
for (unsigned i=0; i<m_wordUses.size(); i++) {
|
||||
if (!m_wholeUse && !m_wordUses[i] && m_wordAssignps[i] && !m_wordComplex[i]) {
|
||||
deleteAssign (m_wordAssignps[i]); m_wordAssignps[i]=NULL;
|
||||
for (unsigned i=0; i<m_words.size(); i++) {
|
||||
if (!m_whole.m_use && !m_words[i].m_use && m_words[i].m_assignp && !m_words[i].m_complex) {
|
||||
deleteAssign (m_words[i].m_assignp); m_words[i].m_assignp=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// See if any variables have changed value since we determined subst value, as a visitor of each AstNode
|
||||
|
||||
class SubstUseVisitor : public SubstBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// See SubstVisitor
|
||||
//
|
||||
// STATE
|
||||
int m_origStep; // Step number where subst was recorded
|
||||
bool m_ok; // No misassignments found
|
||||
|
||||
// METHODS
|
||||
SubstVarEntry* findEntryp(AstVarRef* nodep) {
|
||||
return (SubstVarEntry*)(nodep->varp()->userp()); // Might be NULL
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
SubstVarEntry* entryp = findEntryp (nodep);
|
||||
if (entryp) {
|
||||
// Don't sweat it. We assign a new temp variable for every new assignment,
|
||||
// so there's no way we'd ever replace a old value.
|
||||
} else {
|
||||
// A simple variable; needs checking.
|
||||
if (m_origStep < nodep->varp()->user2()) {
|
||||
if (m_ok) UINFO(9," RHS variable changed since subst recorded: "<<nodep<<endl);
|
||||
m_ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {} // Accelerate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
SubstUseVisitor(AstNode* nodep, int origStep) {
|
||||
UINFO(9, " SubstUseVisitor "<<origStep<<" "<<nodep<<endl);
|
||||
m_ok = true;
|
||||
m_origStep = origStep;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~SubstUseVisitor() {}
|
||||
// METHODS
|
||||
bool ok() const { return m_ok; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Subst state, as a visitor of each AstNode
|
||||
|
||||
class SubstVisitor : public SubstBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Passed to SubstElimVisitor
|
||||
// Passed to SubstUseVisitor
|
||||
// AstVar::userp -> SubstVar* for usage var, 0=not set yet
|
||||
// AstVar::user2 -> int step number for last assignment, 0=not set yet
|
||||
//
|
||||
// STATE
|
||||
vector<SubstVarEntry*> m_entryps; // Nodes to delete when we are finished
|
||||
int m_ops; // Number of operators on assign rhs
|
||||
int m_assignStep; // Assignment number to determine var lifetime
|
||||
V3Double0 m_statSubsts; // Statistic tracking
|
||||
|
||||
enum { SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
|
||||
@@ -178,6 +256,7 @@ private:
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
m_ops = 0;
|
||||
m_assignStep++;
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
bool hit=false;
|
||||
if (AstVarRef* varrefp = nodep->lhsp()->castVarRef()) {
|
||||
@@ -186,10 +265,10 @@ private:
|
||||
hit = true;
|
||||
if (m_ops > SUBST_MAX_OPS_SUBST) {
|
||||
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
|
||||
entryp->assignComplex();
|
||||
entryp->assignComplex(m_assignStep);
|
||||
} else {
|
||||
UINFO(8," ASSIGNwhole "<<varrefp<<endl);
|
||||
entryp->assignWhole(nodep);
|
||||
entryp->assignWhole(m_assignStep, nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,10 +281,10 @@ private:
|
||||
hit = true;
|
||||
if (m_ops > SUBST_MAX_OPS_SUBST) {
|
||||
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
|
||||
entryp->assignWordComplex(word);
|
||||
entryp->assignWordComplex(m_assignStep, word);
|
||||
} else {
|
||||
UINFO(8," ASSIGNword"<<word<<" "<<varrefp<<endl);
|
||||
entryp->assignWord(word, nodep);
|
||||
entryp->assignWord(m_assignStep, word, nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,7 +317,13 @@ private:
|
||||
UINFO(8," USEword"<<word<<" "<<varrefp<<endl);
|
||||
SubstVarEntry* entryp = getEntryp(varrefp);
|
||||
if (AstNode* substp = entryp->substWord (nodep, word)) {
|
||||
replaceSubstEtc(nodep, substp); nodep=NULL;
|
||||
// Check that the RHS hasn't changed value since we recorded it.
|
||||
SubstUseVisitor visitor (substp, entryp->getWordStep(word));
|
||||
if (visitor.ok()) {
|
||||
replaceSubstEtc(nodep, substp); nodep=NULL;
|
||||
} else {
|
||||
entryp->consumeWord(word);
|
||||
}
|
||||
} else {
|
||||
entryp->consumeWord(word);
|
||||
}
|
||||
@@ -247,14 +332,27 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
// Any variable
|
||||
if (nodep->lvalue()) {
|
||||
m_assignStep++;
|
||||
nodep->varp()->user2(m_assignStep);
|
||||
UINFO(9, " ASSIGNstep u2="<<nodep->varp()->user2()<<" "<<nodep<<endl);
|
||||
}
|
||||
if (nodep->varp()->isStatementTemp()) {
|
||||
SubstVarEntry* entryp = getEntryp (nodep);
|
||||
if (nodep->lvalue()) {
|
||||
UINFO(8," ASSIGNcpx "<<nodep<<endl);
|
||||
entryp->assignComplex();
|
||||
entryp->assignComplex(m_assignStep);
|
||||
} else if (AstNode* substp = entryp->substWhole(nodep)) {
|
||||
UINFO(8," USEwhole "<<nodep<<endl);
|
||||
replaceSubstEtc(nodep, substp); nodep=NULL;
|
||||
// Check that the RHS hasn't changed value since we recorded it.
|
||||
SubstUseVisitor visitor (substp, entryp->getWholeStep());
|
||||
if (visitor.ok()) {
|
||||
UINFO(8," USEwhole "<<nodep<<endl);
|
||||
replaceSubstEtc(nodep, substp); nodep=NULL;
|
||||
} else {
|
||||
UINFO(8," USEwholeButChg "<<nodep<<endl);
|
||||
entryp->consumeWhole();
|
||||
}
|
||||
} else { // Consumed w/o substitute
|
||||
UINFO(8," USEwtf "<<nodep<<endl);
|
||||
entryp->consumeWhole();
|
||||
@@ -262,6 +360,7 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {}
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
m_ops++;
|
||||
if (!nodep->isSubstOptimizable()) {
|
||||
@@ -273,7 +372,9 @@ public:
|
||||
// CONSTUCTORS
|
||||
SubstVisitor(AstNode* nodep) {
|
||||
AstNode::userClearTree(); // userp() used on entire tree
|
||||
AstNode::user2ClearTree(); // user2p() used on entire tree
|
||||
m_ops = 0;
|
||||
m_assignStep = 0;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~SubstVisitor() {
|
||||
|
||||
+310
-102
@@ -39,6 +39,54 @@
|
||||
#include "V3Inst.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3Graph.h"
|
||||
|
||||
//######################################################################
|
||||
// Graph subclasses
|
||||
|
||||
class TaskBaseVertex : public V3GraphVertex {
|
||||
AstNode* m_impurep; // Node causing impure function w/ outside references
|
||||
bool m_noInline; // Marked with pragma
|
||||
public:
|
||||
TaskBaseVertex(V3Graph* graphp)
|
||||
: V3GraphVertex(graphp), m_impurep(NULL), m_noInline(false) {}
|
||||
virtual ~TaskBaseVertex() {}
|
||||
bool pure() const { return m_impurep==NULL; }
|
||||
AstNode* impureNode() const { return m_impurep; }
|
||||
void impure(AstNode* nodep) { m_impurep = nodep; }
|
||||
bool noInline() const { return m_noInline; }
|
||||
void noInline(bool flag) { m_noInline = flag; }
|
||||
};
|
||||
|
||||
class TaskFTaskVertex : public TaskBaseVertex {
|
||||
// Every task gets a vertex, and we link tasks together based on funcrefs.
|
||||
AstNodeFTask* m_nodep;
|
||||
public:
|
||||
TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep)
|
||||
: TaskBaseVertex(graphp), m_nodep(nodep) {}
|
||||
virtual ~TaskFTaskVertex() {}
|
||||
AstNodeFTask* nodep() const { return m_nodep; }
|
||||
virtual string name() const { return nodep()->name(); }
|
||||
virtual string dotColor() const { return pure() ? "black" : "red"; }
|
||||
};
|
||||
|
||||
class TaskCodeVertex : public TaskBaseVertex {
|
||||
// Top vertex for all calls not under another task
|
||||
public:
|
||||
TaskCodeVertex(V3Graph* graphp)
|
||||
: TaskBaseVertex(graphp) {}
|
||||
virtual ~TaskCodeVertex() {}
|
||||
virtual string name() const { return "*CODE*"; }
|
||||
virtual string dotColor() const { return "green"; }
|
||||
};
|
||||
|
||||
class TaskEdge : public V3GraphEdge {
|
||||
public:
|
||||
TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top)
|
||||
: V3GraphEdge(graphp, fromp, top, 1, false) {}
|
||||
virtual ~TaskEdge() {}
|
||||
virtual string dotLabel() const { return "w"+cvtToStr(weight()); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -47,12 +95,17 @@ private:
|
||||
// NODE STATE
|
||||
// Output:
|
||||
// AstNodeFTask::user3p // AstScope* this FTask is under
|
||||
// AstNodeFTask::user4p // GraphFTaskVertex* this FTask is under
|
||||
// AstVar::user4p // GraphFTaskVertex* this variable is declared in
|
||||
|
||||
// TYPES
|
||||
typedef std::map<pair<AstScope*,AstVar*>,AstVarScope*> VarToScopeMap;
|
||||
// MEMBERS
|
||||
VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings
|
||||
AstAssignW* m_assignwp; // Current assignment
|
||||
V3Graph m_callGraph; // Task call graph
|
||||
TaskBaseVertex* m_curVxp; // Current vertex we're adding to
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
AstScope* getScope(AstNodeFTask* nodep) {
|
||||
@@ -65,7 +118,30 @@ public:
|
||||
if (iter == m_varToScopeMap.end()) nodep->v3fatalSrc("No scope for var");
|
||||
return iter->second;
|
||||
}
|
||||
bool ftaskNoInline(AstNodeFTask* nodep) {
|
||||
return (getFTaskVertex(nodep)->noInline());
|
||||
}
|
||||
void checkPurity(AstNodeFTask* nodep) {
|
||||
checkPurity(nodep, getFTaskVertex(nodep));
|
||||
}
|
||||
void checkPurity(AstNodeFTask* nodep, TaskBaseVertex* vxp) {
|
||||
if (!vxp->pure()) {
|
||||
nodep->v3warn(IMPURE,"Unsupported: External variable referenced by non-inlined function/task: "<<nodep->prettyName());
|
||||
vxp->impureNode()->v3warn(IMPURE,"... Location of the external reference: "<<vxp->impureNode()->prettyName());
|
||||
}
|
||||
// And, we need to check all tasks this task calls
|
||||
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
checkPurity(nodep, static_cast<TaskBaseVertex*>(edgep->top()));
|
||||
}
|
||||
}
|
||||
private:
|
||||
TaskBaseVertex* getFTaskVertex(AstNodeFTask* nodep) {
|
||||
if (!nodep->user4p()) {
|
||||
nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep));
|
||||
}
|
||||
return static_cast<TaskBaseVertex*>(nodep->user4p()->castGraphVertex());
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
// Each FTask is unique per-scope, so AstNodeFTaskRefs do not need
|
||||
@@ -90,7 +166,7 @@ private:
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
m_assignwp = nodep;
|
||||
nodep->iterateChildren(*this); // May delete nodep.
|
||||
nodep->iterateChildren(*this); nodep=NULL; // May delete nodep.
|
||||
m_assignwp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
@@ -104,6 +180,37 @@ private:
|
||||
AstNode* alwaysp = new AstAlways (m_assignwp->fileline(), NULL, assignp);
|
||||
m_assignwp->replaceWith(alwaysp); pushDeletep(m_assignwp); m_assignwp=NULL;
|
||||
}
|
||||
// We make multiple edges if a task is called multiple times from another task.
|
||||
new TaskEdge (&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp()));
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
UINFO(9," TASK "<<nodep<<endl);
|
||||
TaskBaseVertex* lastVxp = m_curVxp;
|
||||
m_curVxp = getFTaskVertex(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
m_curVxp = lastVxp;
|
||||
}
|
||||
virtual void visit(AstPragma* nodep, AstNUser*) {
|
||||
if (nodep->pragType() == AstPragmaType::NO_INLINE_TASK) {
|
||||
// Just mark for the next steps, and we're done with it.
|
||||
m_curVxp->noInline(true);
|
||||
nodep->unlinkFrBack()->deleteTree();
|
||||
}
|
||||
else {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user4p(m_curVxp); // Remember what task it's under
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->varp()->user4p() != m_curVxp) {
|
||||
if (m_curVxp->pure()) {
|
||||
m_curVxp->impure(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
@@ -112,10 +219,16 @@ private:
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
TaskStateVisitor(AstNode* nodep) {
|
||||
TaskStateVisitor(AstNetlist* nodep) {
|
||||
m_assignwp = NULL;
|
||||
m_curVxp = new TaskCodeVertex(&m_callGraph);
|
||||
AstNode::user3ClearTree();
|
||||
AstNode::user4ClearTree();
|
||||
//
|
||||
nodep->iterateAndNext(*this, NULL);
|
||||
//
|
||||
m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue);
|
||||
m_callGraph.dumpDotFilePrefixed("task_call");
|
||||
}
|
||||
virtual ~TaskStateVisitor() {}
|
||||
};
|
||||
@@ -165,6 +278,7 @@ private:
|
||||
// AstNodeFTask::user // True if its been expanded
|
||||
// Each funccall
|
||||
// AstVar::user2p // AstVarScope* to replace varref with
|
||||
// AstNodeFTask::user5p // AstCFunc* created for non-inlined tasks
|
||||
|
||||
// TYPES
|
||||
enum InsertMode {
|
||||
@@ -207,79 +321,81 @@ private:
|
||||
//
|
||||
// Create input variables
|
||||
AstNode::user2ClearTree();
|
||||
AstNode* pinp = refp->pinsp();
|
||||
AstNode* nextpinp = pinp;
|
||||
AstNode* nextstmtp;
|
||||
for (AstNode* stmtp = newbodysp; stmtp; pinp=nextpinp, stmtp=nextstmtp) {
|
||||
nextstmtp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
portp->unlinkFrBack(); // Remove it from the clone (not original)
|
||||
pushDeletep(portp);
|
||||
if (portp->isIO()) {
|
||||
if (pinp==NULL) {
|
||||
refp->v3error("Too few arguments in function call");
|
||||
pinp = new AstConst(refp->fileline(), 0);
|
||||
m_modp->addStmtp(pinp); // For below unlink
|
||||
}
|
||||
UINFO(9, " Port "<<portp<<endl);
|
||||
UINFO(9, " pin "<<pinp<<endl);
|
||||
//
|
||||
nextpinp = pinp->nextp();
|
||||
pinp->unlinkFrBack(); // Relinked to assignment below
|
||||
//
|
||||
if (portp->isInout()) {
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
// Connect to this exact variable
|
||||
AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope");
|
||||
portp->user2p(localVscp);
|
||||
} else {
|
||||
pinp->v3error("Unsupported: Function/task input argument is not simple variable");
|
||||
{
|
||||
AstNode* pinp = refp->pinsp();
|
||||
AstNode* nextpinp = pinp;
|
||||
AstNode* nextstmtp;
|
||||
for (AstNode* stmtp = newbodysp; stmtp; pinp=nextpinp, stmtp=nextstmtp) {
|
||||
nextstmtp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
portp->unlinkFrBack(); // Remove it from the clone (not original)
|
||||
pushDeletep(portp);
|
||||
if (portp->isIO()) {
|
||||
if (pinp==NULL) {
|
||||
refp->v3error("Too few arguments in function call");
|
||||
pinp = new AstConst(refp->fileline(), 0);
|
||||
m_modp->addStmtp(pinp); // For below unlink
|
||||
}
|
||||
UINFO(9, " Port "<<portp<<endl);
|
||||
UINFO(9, " pin "<<pinp<<endl);
|
||||
//
|
||||
nextpinp = pinp->nextp();
|
||||
pinp->unlinkFrBack(); // Relinked to assignment below
|
||||
//
|
||||
if (portp->isInout()) {
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
// Connect to this exact variable
|
||||
AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope");
|
||||
portp->user2p(localVscp);
|
||||
} else {
|
||||
pinp->v3warn(TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
|
||||
}
|
||||
}
|
||||
else if (portp->isOutput() && outvscp) {
|
||||
refp->v3error("Outputs not allowed in function declarations");
|
||||
}
|
||||
else if (portp->isOutput()) {
|
||||
// Make output variables
|
||||
// Correct lvalue; we didn't know when we linked
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
varrefp->lvalue(true);
|
||||
} else {
|
||||
pinp->v3warn(TASKNSVAR,"Unsupported: Task output pin connected to non-variable");
|
||||
}
|
||||
// Even if it's referencing a varref, we still make a temporary
|
||||
// Else task(x,x,x) might produce incorrect results
|
||||
AstVarScope* outvscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(outvscp);
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
pinp,
|
||||
new AstVarRef(outvscp->fileline(), outvscp, false));
|
||||
// Put assignment BEHIND of all other statements
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
else if (portp->isInput()) {
|
||||
// Make input variable
|
||||
AstVarScope* inVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(inVscp);
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
new AstVarRef(inVscp->fileline(), inVscp, true),
|
||||
pinp);
|
||||
// Put assignment in FRONT of all other statements
|
||||
if (AstNode* afterp = beginp->nextp()) {
|
||||
afterp->unlinkFrBackWithNext();
|
||||
assp->addNext(afterp);
|
||||
}
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
}
|
||||
else if (portp->isOutput() && outvscp) {
|
||||
refp->v3error("Outputs not allowed in function declarations");
|
||||
else { // Var is not I/O
|
||||
// Move it to a new localized variable
|
||||
AstVarScope* localVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(localVscp);
|
||||
}
|
||||
else if (portp->isOutput()) {
|
||||
// Make output variables
|
||||
// Correct lvalue; we didn't know when we linked
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
varrefp->lvalue(true);
|
||||
} else {
|
||||
pinp->v3error("Unsupported: Task output pin connected to non-variable");
|
||||
}
|
||||
// Even if it's referencing a varref, we still make a temporary
|
||||
// Else task(x,x,x) might produce incorrect results
|
||||
AstVarScope* outvscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(outvscp);
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
pinp,
|
||||
new AstVarRef(outvscp->fileline(), outvscp, false));
|
||||
// Put assignment BEHIND of all other statements
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
else if (portp->isInput()) {
|
||||
// Make input variable
|
||||
AstVarScope* inVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(inVscp);
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
new AstVarRef(inVscp->fileline(), inVscp, true),
|
||||
pinp);
|
||||
// Put assignment in FRONT of all other statements
|
||||
if (AstNode* afterp = beginp->nextp()) {
|
||||
afterp->unlinkFrBackWithNext();
|
||||
assp->addNext(afterp);
|
||||
}
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
}
|
||||
else { // Var is not I/O
|
||||
// Move it to a new localized variable
|
||||
AstVarScope* localVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
|
||||
portp->user2p(localVscp);
|
||||
}
|
||||
}
|
||||
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
|
||||
}
|
||||
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
|
||||
// Create function output variables
|
||||
if (outvscp) {
|
||||
//UINFO(0, "setflag on "<<funcp->fvarp()<<" to "<<outvscp<<endl);
|
||||
@@ -292,9 +408,71 @@ private:
|
||||
return beginp;
|
||||
}
|
||||
|
||||
AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) {
|
||||
// outvscp is the variable for functions only, if NULL, it's a task
|
||||
if (!refp->taskp()) refp->v3fatalSrc("Unlinked?");
|
||||
AstCFunc* cfuncp = refp->taskp()->user5p()->castNode()->castCFunc();
|
||||
|
||||
AstCFunc* makeUserFunc(AstNodeFTask* nodep) {
|
||||
// Given a already cloned node, make a public C function.
|
||||
if (!cfuncp) refp->v3fatalSrc("No non-inline task associated with this task call?");
|
||||
//
|
||||
AstNode* beginp = new AstComment(refp->fileline(), (string)("Function: ")+refp->name());
|
||||
AstCCall* ccallp = new AstCCall(refp->fileline(), cfuncp, NULL);
|
||||
beginp->addNext(ccallp);
|
||||
// Convert complicated outputs to temp signals
|
||||
{
|
||||
AstNode* pinp = refp->pinsp();
|
||||
AstNode* nextpinp = pinp;
|
||||
AstNode* nextstmtp;
|
||||
for (AstNode* stmtp = refp->taskp()->stmtsp(); stmtp; pinp=nextpinp, stmtp=nextstmtp) {
|
||||
nextstmtp = stmtp->nextp();
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO()) {
|
||||
UINFO(9, " Port "<<portp<<endl);
|
||||
UINFO(9, " pin "<<pinp<<endl);
|
||||
//
|
||||
nextpinp = pinp->nextp();
|
||||
//
|
||||
if (portp->isInout()) {
|
||||
if (pinp->castVarRef()) {
|
||||
// Connect to this exact variable
|
||||
} else {
|
||||
pinp->v3warn(TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
|
||||
}
|
||||
}
|
||||
else if (portp->isOutput()) {
|
||||
// Make output variables
|
||||
// Correct lvalue; we didn't know when we linked
|
||||
if (AstVarRef* varrefp = pinp->castVarRef()) {
|
||||
varrefp->lvalue(true);
|
||||
} else {
|
||||
pinp->v3warn(TASKNSVAR,"Unsupported: Task output pin connected to non-variable");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
|
||||
}
|
||||
// First argument is symbol table, then output if a function
|
||||
ccallp->argTypes("vlSymsp");
|
||||
if (outvscp) {
|
||||
ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true));
|
||||
}
|
||||
// Create connections
|
||||
AstNode* nextpinp;
|
||||
for (AstNode* pinp = refp->pinsp(); pinp; pinp=nextpinp) {
|
||||
nextpinp = pinp->nextp();
|
||||
// Move pin to the CCall
|
||||
pinp->unlinkFrBack();
|
||||
ccallp->addArgsp(pinp);
|
||||
}
|
||||
if (debug()>=9) { beginp->dumpTree(cout,"-nitask: "); }
|
||||
return beginp;
|
||||
}
|
||||
|
||||
|
||||
AstCFunc* makeUserFunc(AstNodeFTask* nodep, bool forUser) {
|
||||
// Given a already cloned node, make a public C function, or a non-inline C function
|
||||
// Probably some of this work should be done later, but...
|
||||
// should the type of the function be bool/uint32/64 etc (based on lookup) or IData?
|
||||
AstNode::user2ClearTree();
|
||||
@@ -305,6 +483,7 @@ private:
|
||||
if (NULL!=(portp = nodep->castFunc()->fvarp()->castVar())) {
|
||||
if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var");
|
||||
if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)");
|
||||
if (!forUser) portp->funcReturn(false); // Converting return to 'outputs'
|
||||
portp->unlinkFrBack();
|
||||
rtnvarp = portp;
|
||||
rtnvarp->funcLocal(true);
|
||||
@@ -315,20 +494,28 @@ private:
|
||||
nodep->v3fatalSrc("function without function output variable");
|
||||
}
|
||||
}
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), nodep->name(),
|
||||
m_scopep,
|
||||
(rtnvarp?rtnvarp->cType():""));
|
||||
if (rtnvarp) funcp->addArgsp(rtnvarp);
|
||||
funcp->dontCombine(true);
|
||||
funcp->funcPublic(true);
|
||||
funcp->entryPoint(true);
|
||||
funcp->isStatic(false);
|
||||
AstCFunc* cfuncp = new AstCFunc(nodep->fileline(),
|
||||
string(forUser?"":"__VnoInFunc_") + nodep->name(),
|
||||
m_scopep,
|
||||
((forUser && rtnvarp)?rtnvarp->cType():""));
|
||||
cfuncp->dontCombine(true);
|
||||
cfuncp->entryPoint(true);
|
||||
cfuncp->funcPublic(forUser);
|
||||
cfuncp->isStatic(!forUser);
|
||||
|
||||
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
|
||||
funcp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(),
|
||||
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
if (forUser) {
|
||||
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
|
||||
cfuncp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(),
|
||||
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
} else {
|
||||
// Need symbol table
|
||||
cfuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
}
|
||||
// Fake output variable if was a function
|
||||
if (rtnvarp) cfuncp->addArgsp(rtnvarp);
|
||||
|
||||
cfuncp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
|
||||
// Create list of arguments and move to function
|
||||
for (AstNode* nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp=nextp) {
|
||||
@@ -338,7 +525,7 @@ private:
|
||||
// Move it to new function
|
||||
portp->unlinkFrBack();
|
||||
portp->funcLocal(true);
|
||||
funcp->addArgsp(portp);
|
||||
cfuncp->addArgsp(portp);
|
||||
} else {
|
||||
// "Normal" variable, mark inside function
|
||||
portp->funcLocal(true);
|
||||
@@ -350,18 +537,19 @@ private:
|
||||
}
|
||||
// Move body
|
||||
AstNode* bodysp = nodep->stmtsp();
|
||||
if (bodysp) { bodysp->unlinkFrBackWithNext(); funcp->addStmtsp(bodysp); }
|
||||
if (bodysp) { bodysp->unlinkFrBackWithNext(); cfuncp->addStmtsp(bodysp); }
|
||||
// Return statement
|
||||
if (rtnvscp) {
|
||||
funcp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
|
||||
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
|
||||
if (rtnvscp && forUser) {
|
||||
cfuncp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
|
||||
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
|
||||
}
|
||||
// Replace variable refs
|
||||
TaskRelinkVisitor visit (funcp);
|
||||
TaskRelinkVisitor visit (cfuncp);
|
||||
// Delete rest of cloned task and return new func
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
if (debug()>=9) { funcp->dumpTree(cout,"-userFunc: "); }
|
||||
return funcp;
|
||||
if (debug()>=9 && forUser) { cfuncp->dumpTree(cout,"-userFunc: "); }
|
||||
if (debug()>=9 && !forUser) { cfuncp->dumpTree(cout,"-noInFunc: "); }
|
||||
return cfuncp;
|
||||
}
|
||||
|
||||
void iterateIntoFTask(AstNodeFTask* nodep) {
|
||||
@@ -421,7 +609,12 @@ private:
|
||||
if (debug()>=9) { nodep->dumpTree(cout,"-inltask:"); }
|
||||
// Create cloned statements
|
||||
string namePrefix = "__Vtask_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
|
||||
AstNode* beginp = createInlinedFTask(nodep, namePrefix, NULL);
|
||||
AstNode* beginp;
|
||||
if (m_statep->ftaskNoInline(nodep->taskp())) {
|
||||
beginp = createNonInlinedFTask(nodep, namePrefix, NULL);
|
||||
} else {
|
||||
beginp = createInlinedFTask(nodep, namePrefix, NULL);
|
||||
}
|
||||
// Replace the ref
|
||||
nodep->replaceWith(beginp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
@@ -442,7 +635,13 @@ private:
|
||||
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
|
||||
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
|
||||
|
||||
AstNode* beginp = createInlinedFTask(nodep, namePrefix, outvscp);
|
||||
AstNode* beginp;
|
||||
if (m_statep->ftaskNoInline(nodep->taskp())) {
|
||||
// This may share VarScope's with a public task, if any. Yuk.
|
||||
beginp = createNonInlinedFTask(nodep, namePrefix, outvscp);
|
||||
} else {
|
||||
beginp = createInlinedFTask(nodep, namePrefix, outvscp);
|
||||
}
|
||||
// Replace the ref
|
||||
AstVarRef* outrefp = new AstVarRef (nodep->fileline(), outvscp, false);
|
||||
nodep->replaceWith(outrefp);
|
||||
@@ -450,27 +649,34 @@ private:
|
||||
insertBeforeStmt(nodep, beginp);
|
||||
// Cleanup
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
UINFO(4," Done.\n");
|
||||
UINFO(4," Func REF Done.\n");
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
UINFO(4," Inline "<<nodep<<endl);
|
||||
InsertMode prevInsMode = m_insMode;
|
||||
AstNode* prevInsStmtp = m_insStmtp;
|
||||
m_insMode = IM_BEFORE;
|
||||
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
|
||||
if (!nodep->user()) {
|
||||
// Expand functions in it & Mark for later delete
|
||||
// Expand functions in it
|
||||
nodep->user(true);
|
||||
if (!nodep->taskPublic()) {
|
||||
nodep->unlinkFrBack();
|
||||
} else {
|
||||
if (nodep->taskPublic()) {
|
||||
// Clone it first, because we may have later FTaskRef's that still need
|
||||
// the original version.
|
||||
AstNodeFTask* clonedFuncp = nodep->cloneTree(false)->castNodeFTask();
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp);
|
||||
// Replace it
|
||||
nodep->replaceWith(cfuncp);
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, true);
|
||||
nodep->addNextHere(cfuncp);
|
||||
iterateIntoFTask(clonedFuncp); // Do the clone too
|
||||
}
|
||||
if (m_statep->ftaskNoInline(nodep)) {
|
||||
m_statep->checkPurity(nodep);
|
||||
AstNodeFTask* clonedFuncp = nodep->cloneTree(false)->castNodeFTask();
|
||||
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, false);
|
||||
nodep->user5p(cfuncp);
|
||||
nodep->addNextHere(cfuncp);
|
||||
iterateIntoFTask(clonedFuncp); // Do the clone too
|
||||
}
|
||||
|
||||
// Any variables inside the function still have varscopes pointing to them.
|
||||
// We're going to delete the vars, so delete the varscopes.
|
||||
if (nodep->castFunc()) {
|
||||
@@ -489,6 +695,7 @@ private:
|
||||
}
|
||||
}
|
||||
// Just push, as other references to func may remain until visitor exits
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
m_insMode = prevInsMode;
|
||||
@@ -532,6 +739,7 @@ public:
|
||||
m_scopep = NULL;
|
||||
m_insStmtp = NULL;
|
||||
AstNode::userClearTree();
|
||||
AstNode::user5ClearTree();
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~TaskVisitor() {}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
//**********************************************************************
|
||||
//**** Version and host name
|
||||
|
||||
#define DTVERSION "Verilator 3.620 10/04/2006"
|
||||
#define DTVERSION "Verilator 3.622 10/17/2006"
|
||||
|
||||
//**********************************************************************
|
||||
//**** Functions
|
||||
|
||||
@@ -429,6 +429,7 @@ escid \\[^ \t\f\r\n]+
|
||||
<VLG,PSL>"/*verilator full_case*/" {yylval.fileline = CRELINE(); return yVL_FULL_CASE;}
|
||||
<VLG,PSL>"/*verilator inline_module*/" {yylval.fileline = CRELINE(); return yVL_INLINE_MODULE;}
|
||||
<VLG,PSL>"/*verilator no_inline_module*/" {yylval.fileline = CRELINE(); return yVL_NO_INLINE_MODULE;}
|
||||
<VLG,PSL>"/*verilator no_inline_task*/" {yylval.fileline = CRELINE(); return yVL_NO_INLINE_TASK;}
|
||||
<VLG,PSL>"/*verilator one_cold*/" {yylval.fileline = CRELINE(); return yVL_ONE_COLD;}
|
||||
<VLG,PSL>"/*verilator one_hot*/" {yylval.fileline = CRELINE(); return yVL_ONE_HOT;}
|
||||
<VLG,PSL>"/*verilator parallel_case*/" {yylval.fileline = CRELINE(); return yVL_PARALLEL_CASE;}
|
||||
|
||||
+3
-1
@@ -168,6 +168,7 @@ class AstSenTree;
|
||||
%token<fileline> yVL_FULL_CASE "/*verilator full_case*/"
|
||||
%token<fileline> yVL_INLINE_MODULE "/*verilator inline_module*/"
|
||||
%token<fileline> yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/"
|
||||
%token<fileline> yVL_NO_INLINE_TASK "/*verilator no_inline_task*/"
|
||||
%token<fileline> yVL_ONE_COLD "/*verilator one_cold*/"
|
||||
%token<fileline> yVL_ONE_HOT "/*verilator one_hot*/"
|
||||
%token<fileline> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
|
||||
@@ -729,7 +730,8 @@ funcVarList: funcVar { $$ = $1; }
|
||||
|
||||
funcVar: ioDecl { $$ = $1; }
|
||||
| varDecl { $$ = $1; }
|
||||
| yVL_PUBLIC { $$ = new AstPragma ($1,AstPragmaType::PUBLIC_TASK); }
|
||||
| yVL_PUBLIC { $$ = new AstPragma($1,AstPragmaType::PUBLIC_TASK); }
|
||||
| yVL_NO_INLINE_TASK { $$ = new AstPragma($1,AstPragmaType::NO_INLINE_TASK); }
|
||||
;
|
||||
|
||||
constExpr: expr { $$ = $1; }
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@ include Vtop.mk
|
||||
CPPFLAGS += -DVL_DEBUG=1
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
CPPFLAGS += -DVL_THREADED=1
|
||||
CPPFLAGS += -W
|
||||
CPPFLAGS += -Werror
|
||||
CPPFLAGS += -W -Werror -Wall
|
||||
#CPPFLAGS += -Wno-unused-variable # Instead, add VL_ATTR_UNUSED in gen'ed code
|
||||
#CPPFLAGS += -pedantic-errors
|
||||
endif
|
||||
|
||||
|
||||
@@ -673,8 +673,8 @@ sub verilator_version {
|
||||
sub files_identical {
|
||||
my $fn1 = shift;
|
||||
my $fn2 = shift;
|
||||
my $f1 = IO::File->new ("<$fn1") or die "%Error: $! $fn1,";
|
||||
my $f2 = IO::File->new ("<$fn2") or die "%Error: $! $fn2,";
|
||||
my $f1 = IO::File->new ("<$fn1"); if (!$f1) { warn "%Error: $! $fn1\n"; return 0; }
|
||||
my $f2 = IO::File->new ("<$fn2"); if (!$f2) { warn "%Error: $! $fn2\n"; return 0; }
|
||||
my @l1 = $f1->getlines();
|
||||
my @l2 = $f2->getlines();
|
||||
my $nl = $#l1; $nl = $#l2 if ($#l2 > $nl);
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
[2] crc=0000000000000097 1410
|
||||
[3] crc=000000000000012e 1410
|
||||
[4] crc=000000000000025d 1410
|
||||
[5] crc=00000000000004ba 1410
|
||||
[6] crc=0000000000000974 1410
|
||||
[7] crc=00000000000012e9 1410
|
||||
[8] crc=00000000000025d3 1410
|
||||
[9] crc=0000000000004ba7 1410
|
||||
[10] crc=000000000000974e 1410
|
||||
[11] crc=0000000000012e9d 1410
|
||||
[12] crc=0000000000025d3a 1410
|
||||
[13] crc=000000000004ba74 1410
|
||||
[14] crc=00000000000974e9 1410
|
||||
[15] crc=000000000012e9d3 1410
|
||||
[16] crc=000000000025d3a7 1410
|
||||
[17] crc=00000000004ba74e 1410
|
||||
[18] crc=0000000000974e9d 1410
|
||||
[19] crc=00000000012e9d3a 1410
|
||||
[20] crc=00000000025d3a74 1410
|
||||
[21] crc=0000000004ba74e9 1410
|
||||
[22] crc=000000000974e9d3 1304a:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039;17 1304b:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039203233 1304c:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020313030392032332031333033;4 1304d:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039203233203133303320313338 1304e:203130303920323320313330332031333820202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020 1304: 1009 23 1303 138
|
||||
[23] crc=0000000012e9d3a7 1313: 1009 46 1309 1311 143 1312
|
||||
[24] crc=0000000025d3a74e 1129: 1009 172 407 175 408 409 410 1106
|
||||
[25] crc=000000004ba74e9d 1017: 1009 223 1014 880 885 1015 1016 1007
|
||||
[26] crc=00000000974e9d3a 1231: 1229 967 1230 718
|
||||
[27] crc=000000012e9d3a74 1410
|
||||
[28] crc=000000025d3a74e9 1370: 1009 58 1369 19
|
||||
[29] crc=00000004ba74e9d3 1036: 1009 194 1033 1034 1008 1035 880
|
||||
[30] crc=0000000974e9d3a7 1409:i
|
||||
[31] crc=00000012e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
|
||||
[32] crc=00000025d3a74e9d 1383:§
|
||||
[33] crc=0000004ba74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
|
||||
[34] crc=000000974e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
|
||||
[35] crc=0000012e9d3a74e9 1231: 1228 979 1230 713
|
||||
[36] crc=0000025d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
|
||||
[37] crc=000004ba74e9d3a7 1409:i
|
||||
[38] crc=00000974e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
|
||||
[39] crc=000012e9d3a74e9d 1383:§
|
||||
[40] crc=000025d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
|
||||
[41] crc=00004ba74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
|
||||
[42] crc=0000974e9d3a74e9 1231: 1228 979 1230 713
|
||||
[43] crc=00012e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
|
||||
[44] crc=00025d3a74e9d3a7 1409:i
|
||||
[45] crc=0004ba74e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
|
||||
[46] crc=000974e9d3a74e9d 1383:§
|
||||
[47] crc=0012e9d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
|
||||
[48] crc=0025d3a74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
|
||||
[49] crc=004ba74e9d3a74e9 1231: 1228 979 1230 713
|
||||
[50] crc=00974e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
|
||||
[51] crc=012e9d3a74e9d3a7 1409:i
|
||||
[52] crc=025d3a74e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
|
||||
[53] crc=04ba74e9d3a74e9d 1383:§
|
||||
[54] crc=0974e9d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
|
||||
[55] crc=12e9d3a74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
|
||||
[56] crc=25d3a74e9d3a74e9 1231: 1228 979 1230 713
|
||||
[57] crc=4ba74e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
|
||||
[58] crc=974e9d3a74e9d3a7 1409:i
|
||||
[59] crc=2e9d3a74e9d3a74f 1321: 1009 29 1320 137 144 141 138 149
|
||||
[60] crc=5d3a74e9d3a74e9e 1383:§
|
||||
[61] crc=ba74e9d3a74e9d3d 1021: 1009 216 1018 882 884 1019 1020 1007
|
||||
[62] crc=74e9d3a74e9d3a7b 1017: 1009 197 1014 882 883 1015 1016 1008
|
||||
[63] crc=e9d3a74e9d3a74f7 1231: 1228 979 1230 713
|
||||
[64] crc=d3a74e9d3a74e9ef 1013: 1009 194 1011 1006 1008 1012 880
|
||||
[65] crc=a74e9d3a74e9d3df 1409:i
|
||||
[66] crc=4e9d3a74e9d3a7bf 1321: 1009 29 1320 137 144 141 145 149
|
||||
[67] crc=9d3a74e9d3a74f7e 1383:§
|
||||
[68] crc=3a74e9d3a74e9efc 1021: 1009 216 1018 882 884 1019 1020 1007
|
||||
[69] crc=74e9d3a74e9d3df9 1017: 1009 197 1014 882 883 1015 1016 1008
|
||||
[70] crc=e9d3a74e9d3a7bf3 1231: 1228 979 1230 713
|
||||
[71] crc=d3a74e9d3a74f7e6 1013: 1009 194 1011 1006 1008 1012 880
|
||||
[72] crc=a74e9d3a74e9efcc 1409:i
|
||||
[73] crc=4e9d3a74e9d3df98 1321: 1009 29 1320 137 147 149 143 142
|
||||
[74] crc=9d3a74e9d3a7bf30 1383:§
|
||||
[75] crc=3a74e9d3a74f7e61 1021: 1009 216 1018 882 885 1019 1020 1007
|
||||
[76] crc=74e9d3a74e9efcc3 1017: 1009 197 1014 882 884 1015 1016 1008
|
||||
[77] crc=e9d3a74e9d3df987 1231: 1228 982 1230 713
|
||||
[78] crc=d3a74e9d3a7bf30f 1013: 1009 194 1011 1006 1008 1012 881 885
|
||||
[79] crc=a74e9d3a74f7e61f 1409:w
|
||||
[80] crc=4e9d3a74e9efcc3f 1321: 1009 30 1320 149 146 146 137 149
|
||||
[81] crc=9d3a74e9d3df987e 1383:ß
|
||||
[82] crc=3a74e9d3a7bf30fc 1021: 1009 225 1018 882 885 1019 1020 1008
|
||||
[83] crc=74e9d3a74f7e61f9 1017: 1009 218 1014 882 884 1015 1016 1008
|
||||
[84] crc=e9d3a74e9efcc3f3 1231: 1228 981 1230 708
|
||||
[85] crc=d3a74e9d3df987e6 1013: 1009 232 1011 1005 1008 1012 881 883
|
||||
[86] crc=a74e9d3a7bf30fcc 1409:s
|
||||
[87] crc=4e9d3a74f7e61f98 1262: 1009 1006 1258 846 1259 1006 1260 833 1261
|
||||
[88] crc=9d3a74e9efcc3f30 1321: 1009 124 1320 146 137 149 137 134
|
||||
[89] crc=3a74e9d3df987e61 1383:˜
|
||||
[90] crc=74e9d3a7bf30fcc3 1036: 1009 215 1033 1034 1008 1035 879
|
||||
@@ -16,12 +16,12 @@ module t (/*AUTOARG*/
|
||||
reg [63:0] crc;
|
||||
`verilator_file_descriptor fd;
|
||||
|
||||
t_case_write_tasks tasks ();
|
||||
t_case_write1_tasks tasks ();
|
||||
|
||||
integer cyc; initial cyc=0;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
$fwrite(fd, "[%03d] ", cyc);
|
||||
$fwrite(fd, "[%0d] crc=%x ", cyc, crc);
|
||||
tasks.big_case(fd, crc[31:0]);
|
||||
$fwrite(fd, "\n");
|
||||
end
|
||||
@@ -32,8 +32,8 @@ module t (/*AUTOARG*/
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
if (cyc==1) begin
|
||||
crc <= 64'h00000000_00000097;
|
||||
$write("Open obj_dir/t_case_write_logger.log\n");
|
||||
fd = $fopen("obj_dir/t_case_write_logger.log", "w");
|
||||
$write("Open obj_dir/t_case_write1_logger.log\n");
|
||||
fd = $fopen("obj_dir/t_case_write1_logger.log", "w");
|
||||
end
|
||||
if (cyc==90) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,89 @@
|
||||
[2] crc=0000000000000097 1009 1410
|
||||
[3] crc=000000000000012e 1009 1410
|
||||
[4] crc=000000000000025d 1009 1410
|
||||
[5] crc=00000000000004ba 1009 1410
|
||||
[6] crc=0000000000000974 1009 1410
|
||||
[7] crc=00000000000012e9 1009 1410
|
||||
[8] crc=00000000000025d3 1009 1410
|
||||
[9] crc=0000000000004ba7 1009 1410
|
||||
[10] crc=000000000000974e 1009 1410
|
||||
[11] crc=0000000000012e9d 1009 1410
|
||||
[12] crc=0000000000025d3a 1009 1410
|
||||
[13] crc=000000000004ba74 1009 1410
|
||||
[14] crc=00000000000974e9 1009 1410
|
||||
[15] crc=000000000012e9d3 1009 1410
|
||||
[16] crc=000000000025d3a7 1009 1410
|
||||
[17] crc=00000000004ba74e 1009 1410
|
||||
[18] crc=0000000000974e9d 1009 1410
|
||||
[19] crc=00000000012e9d3a 1009 1410
|
||||
[20] crc=00000000025d3a74 1009 1410
|
||||
[21] crc=0000000004ba74e9 1009 1410
|
||||
[22] crc=000000000974e9d3 1009 23 1303 138 dude 1304
|
||||
[23] crc=0000000012e9d3a7 1009 46 1309 1311 143 1312 dude 1313
|
||||
[24] crc=0000000025d3a74e 1009 172 407 175 408 409 410 1106 dude 1129
|
||||
[25] crc=000000004ba74e9d 1009 223 1014 880 885 1015 1016:0 1007 dude 1017
|
||||
[26] crc=00000000974e9d3a 1009 1229 967 1230 718 dude 1231
|
||||
[27] crc=000000012e9d3a74 1009 1410
|
||||
[28] crc=000000025d3a74e9 1009 58 1369 19 dude 1370
|
||||
[29] crc=00000004ba74e9d3 1009 194 1033 1034 1008 1035 880 dude 1036
|
||||
[30] crc=0000000974e9d3a7 1009 1409:69
|
||||
[31] crc=00000012e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
|
||||
[32] crc=00000025d3a74e9d 1009 1383:3a7
|
||||
[33] crc=0000004ba74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
|
||||
[34] crc=000000974e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
|
||||
[35] crc=0000012e9d3a74e9 1009 1228 979 1230 713 dude 1231
|
||||
[36] crc=0000025d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
|
||||
[37] crc=000004ba74e9d3a7 1009 1409:69
|
||||
[38] crc=00000974e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
|
||||
[39] crc=000012e9d3a74e9d 1009 1383:3a7
|
||||
[40] crc=000025d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
|
||||
[41] crc=00004ba74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
|
||||
[42] crc=0000974e9d3a74e9 1009 1228 979 1230 713 dude 1231
|
||||
[43] crc=00012e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
|
||||
[44] crc=00025d3a74e9d3a7 1009 1409:69
|
||||
[45] crc=0004ba74e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
|
||||
[46] crc=000974e9d3a74e9d 1009 1383:3a7
|
||||
[47] crc=0012e9d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
|
||||
[48] crc=0025d3a74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
|
||||
[49] crc=004ba74e9d3a74e9 1009 1228 979 1230 713 dude 1231
|
||||
[50] crc=00974e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
|
||||
[51] crc=012e9d3a74e9d3a7 1009 1409:69
|
||||
[52] crc=025d3a74e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
|
||||
[53] crc=04ba74e9d3a74e9d 1009 1383:3a7
|
||||
[54] crc=0974e9d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
|
||||
[55] crc=12e9d3a74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
|
||||
[56] crc=25d3a74e9d3a74e9 1009 1228 979 1230 713 dude 1231
|
||||
[57] crc=4ba74e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
|
||||
[58] crc=974e9d3a74e9d3a7 1009 1409:69
|
||||
[59] crc=2e9d3a74e9d3a74f 1009 29 1320 137 144 141 138 149 dude 1321
|
||||
[60] crc=5d3a74e9d3a74e9e 1009 1383:3a7
|
||||
[61] crc=ba74e9d3a74e9d3d 1009 216 1018 882 884 1019 1020 1007 dude 1021
|
||||
[62] crc=74e9d3a74e9d3a7b 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
|
||||
[63] crc=e9d3a74e9d3a74f7 1009 1228 979 1230 713 dude 1231
|
||||
[64] crc=d3a74e9d3a74e9ef 1009 194 1011 1006 1008 1012 880 dude 1013
|
||||
[65] crc=a74e9d3a74e9d3df 1009 1409:69
|
||||
[66] crc=4e9d3a74e9d3a7bf 1009 29 1320 137 144 141 145 149 dude 1321
|
||||
[67] crc=9d3a74e9d3a74f7e 1009 1383:3a7
|
||||
[68] crc=3a74e9d3a74e9efc 1009 216 1018 882 884 1019 1020 1007 dude 1021
|
||||
[69] crc=74e9d3a74e9d3df9 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
|
||||
[70] crc=e9d3a74e9d3a7bf3 1009 1228 979 1230 713 dude 1231
|
||||
[71] crc=d3a74e9d3a74f7e6 1009 194 1011 1006 1008 1012 880 dude 1013
|
||||
[72] crc=a74e9d3a74e9efcc 1009 1409:69
|
||||
[73] crc=4e9d3a74e9d3df98 1009 29 1320 137 147 149 143 142 dude 1321
|
||||
[74] crc=9d3a74e9d3a7bf30 1009 1383:3a7
|
||||
[75] crc=3a74e9d3a74f7e61 1009 216 1018 882 885 1019 1020 1007 dude 1021
|
||||
[76] crc=74e9d3a74e9efcc3 1009 197 1014 882 884 1015 1016:1 1008 dude 1017
|
||||
[77] crc=e9d3a74e9d3df987 1009 1228 982 1230 713 dude 1231
|
||||
[78] crc=d3a74e9d3a7bf30f 1009 194 1011 1006 1008 1012 881 885 dude 1013
|
||||
[79] crc=a74e9d3a74f7e61f 1009 1409:77
|
||||
[80] crc=4e9d3a74e9efcc3f 1009 30 1320 149 146 146 137 149 dude 1321
|
||||
[81] crc=9d3a74e9d3df987e 1009 1383:3df
|
||||
[82] crc=3a74e9d3a7bf30fc 1009 225 1018 882 885 1019 1020 1008 dude 1021
|
||||
[83] crc=74e9d3a74f7e61f9 1009 218 1014 882 884 1015 1016:1 1008 dude 1017
|
||||
[84] crc=e9d3a74e9efcc3f3 1009 1228 981 1230 708 dude 1231
|
||||
[85] crc=d3a74e9d3df987e6 1009 232 1011 1005 1008 1012 881 883 dude 1013
|
||||
[86] crc=a74e9d3a7bf30fcc 1009 1409:73
|
||||
[87] crc=4e9d3a74f7e61f98 1009 1006 1258 846 1259 1006 1260 833 1261 dude 1262
|
||||
[88] crc=9d3a74e9efcc3f30 1009 124 1320 146 137 149 137 134 dude 1321
|
||||
[89] crc=3a74e9d3df987e61 1009 1383:f98
|
||||
[90] crc=74e9d3a7bf30fcc3 1009 215 1033 1034 1008 1035 879 dude 1036
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2006 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
$golden_out ||= "t/$Last_Self->{name}.out";
|
||||
|
||||
compile (
|
||||
v_flags2 => [$Last_Self->{v3}?"--stats --O3 -x-assign 0":""],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(files_identical("obj_dir/$Last_Self->{name}_logger.log", $golden_out));
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,44 @@
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2006 by Wilson Snyder.
|
||||
|
||||
`include "verilated.v"
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
reg [63:0] crc;
|
||||
`verilator_file_descriptor fd;
|
||||
|
||||
t_case_write2_tasks tasks ();
|
||||
|
||||
integer cyc; initial cyc=0;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
$fwrite(fd, "[%0d] crc=%x ", cyc, crc);
|
||||
tasks.big_case(fd, crc[31:0]);
|
||||
$fwrite(fd, "\n");
|
||||
end
|
||||
|
||||
always @ (posedge clk) begin
|
||||
//$write("[%0t] cyc==%0d crc=%x\n",$time, cyc, crc);
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
if (cyc==1) begin
|
||||
crc <= 64'h00000000_00000097;
|
||||
$write("Open obj_dir/t_case_write2_logger.log\n");
|
||||
fd = $fopen("obj_dir/t_case_write2_logger.log", "w");
|
||||
end
|
||||
if (cyc==90) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
File diff suppressed because it is too large
Load Diff
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
if ($Last_Self->{v3}) {
|
||||
compile ();
|
||||
|
||||
my $outfile = "obj_dir/V".$Last_Self->{name}.".cpp";
|
||||
my @oldstats = stat($outfile);
|
||||
print "Old mtime=",$oldstats[9],"\n";
|
||||
$oldstats[9] or $Last_Self->error("No output file found: $outfile\n");
|
||||
|
||||
sleep (1); # Or else it might take < 1 second to compile and see no diff.
|
||||
|
||||
compile ();
|
||||
|
||||
my @newstats = stat($outfile);
|
||||
print "New mtime=",$newstats[9],"\n";
|
||||
|
||||
($oldstats[9] == $newstats[9])
|
||||
or $Last_Self->error("--skip-identical was ignored -- recompiled\n");
|
||||
}
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,9 @@
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2006 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
endmodule
|
||||
@@ -13,7 +13,7 @@ compile (
|
||||
fails=>$Last_Self->{v3},
|
||||
verilator_flags=> [qw(-sp -Werror-WIDTH)],
|
||||
expect=>
|
||||
'%Error: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST generates 6 bits.
|
||||
'%Error-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST generates 6 bits.
|
||||
%Error: Exiting due to',
|
||||
) if $Last_Self->{v3};
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ module t;
|
||||
flipupperbit(global,4'd12);
|
||||
if (global !== 32'h10100001) $stop;
|
||||
|
||||
if (nil_func(32'h12,32'h12) != 32'h24) $stop;
|
||||
nil_task(32'h012,32'h112,global);
|
||||
if (global !== 32'h124) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
@@ -85,4 +89,19 @@ module t;
|
||||
end
|
||||
endtask
|
||||
|
||||
task nil_task;
|
||||
input [31:0] a;
|
||||
input [31:0] b;
|
||||
output [31:0] q;
|
||||
// verilator no_inline_task
|
||||
q = nil_func(a, b);
|
||||
endtask
|
||||
|
||||
function [31:0] nil_func;
|
||||
input [31:0] fa;
|
||||
input [31:0] fb;
|
||||
// verilator no_inline_task
|
||||
nil_func = fa + fb;
|
||||
endfunction
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id:$
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
@@ -13,7 +13,7 @@ compile (
|
||||
'%Error: t/t_func_bad.v:\d+: Too few arguments in function call
|
||||
%Error: t/t_func_bad.v:\d+: Too many arguments in function call
|
||||
%Error: t/t_func_bad.v:\d+: Too few arguments in function call
|
||||
%Error: t/t_func_bad.v:\d+: Unsupported: Task output pin connected to non-variable
|
||||
%Error-TASKNSVAR: t/t_func_bad.v:\d+: Unsupported: Task output pin connected to non-variable
|
||||
%Error: t/t_func_bad.v:\d+: Outputs not allowed in function declarations
|
||||
%Error: Exiting due to',
|
||||
);
|
||||
|
||||
@@ -39,7 +39,6 @@ module t (/*AUTOARG*/
|
||||
a <= 256'h0e17c88f3d5fe51a982646c8e2bd68c3e236ddfddddbdad20a48e039c9f395b8;
|
||||
divisor <= 61'h1238123771;
|
||||
a[60] <= 1'b0; divisor[60] <= 1'b0; // Unsigned
|
||||
//$display("FIX");
|
||||
if (qq!==61'h00000403ad81c0da) $stop;
|
||||
if (rq!==61'h00000000000090ec) $stop;
|
||||
if (qqs!==61'h00000403ad81c0da) $stop;
|
||||
|
||||
@@ -21,6 +21,9 @@ CPPFLAGS += -DUTIL_PRINTF=sp_log_printf
|
||||
CPPFLAGS += -Wno-deprecated
|
||||
CPPFLAGS += $(SYSTEMC_CXX_FLAGS)
|
||||
CPPFLAGS += $(OPT)
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
#CPPFLAGS += -W -Wall -Wno-char-subscripts -Wno-unused-parameter -Wno-unused-variable -Wno-uninitialized -Werror
|
||||
endif
|
||||
|
||||
LDFLAGS += $(SYSTEMC_CXX_FLAGS)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user